滑动窗口协议实验

[TOC]

实验目的

计算机网络的数据链路层协议保证通信双方在有差错的通信线路上进行无差错的数据传输,是计算机网络各层协议中通信控制功能最典型的一种协议。

本实验实现一个数据链路层协议的数据传送部分,目的在于使学生更好地理解数据链路层协议中的“滑动窗口”技术的基本工作原理,掌握计算机网络协议的基本实现技术。

实验要求

在一个数据链路层的模拟实现环境中,用 C 语言实现下面三个数据链路层协议。

  1. 1比特滑动窗口协议
  2. 回退N帧滑动窗口协议
  3. 选择性重传协议

实验内容

充分理解滑动窗口协议,根据滑动窗口协议,模拟滑动窗口协议中发送端的功能,对系统发送的帧进行缓存并加入窗口等待确认,并在超时或者错误时对部分帧进行重传。

编写停等及退回 N 滑动窗口协议函数,响应系统的发送请求、接收帧 消息以及超时消息,并根据滑动窗口协议进行相应处理。

编写选择性重传协议函数,响应系统的发送请求、接受帧消息以及错误 消息,并根据滑动窗口协议进行相应处理。

实现思路

就按照实验说明书的各种情况依次判断即可,需要一个缓存器frameBuffer,这里由于方便,直接设置了100长度的缓存,足够测试用了。

源码

#include "sysinclude.h"

extern void SendFRAMEPacket(unsigned char *pData, unsigned int len);

#define WINDOW_SIZE_STOP_WAIT 1
#define WINDOW_SIZE_BACK_N_FRAME 4
#define BUFFER_SIZE 100

typedef enum {
    data, ack, nak
} frame_kind;
typedef struct frame_head {
    frame_kind kind;        //帧类型
    unsigned int seq;       //序列号
    unsigned int ack;       //确认号
    unsigned char data[100];//数据
};
typedef struct frame {
    frame_head head;        //帧头
    unsigned int size;      //数据的大小
};

frame frameBuffer[BUFFER_SIZE];

unsigned int exceptFrame = 0;    //期望接收到的确认帧的位置
unsigned int lastFrame = 0;        //下一个要缓存的帧存储的位置
unsigned int nextFrame = 0;        //下一个要发送的帧的位置
/*
* 停等协议测试函数
*/
int stud_slide_window_stop_and_wait(char *pBuffer, int bufferSize, UINT8 messageType) {
    switch (messageType) {
        case MSG_TYPE_SEND: {
            frameBuffer[lastFrame].head = *(frame_head *) pBuffer; //缓存
            frameBuffer[lastFrame].size = bufferSize;
            lastFrame++;
            if (lastFrame - exceptFrame <= WINDOW_SIZE_STOP_WAIT) {
                SendFRAMEPacket((unsigned char *) pBuffer, (unsigned int) bufferSize);
                nextFrame++;
            }
            break;
        }
        case MSG_TYPE_RECEIVE: {
            unsigned int ack = ntohl(((frame_head *) pBuffer)->ack);
            unsigned int exceptAck = ntohl(frameBuffer[exceptFrame].head.seq);
            if (ack == exceptAck) {
                exceptFrame++;
                if (nextFrame < lastFrame) {
                    SendFRAMEPacket((unsigned char *) &(frameBuffer[nextFrame].head), frameBuffer[nextFrame].size);
                    nextFrame++;
                }
            }
            break;
        }
        case MSG_TYPE_TIMEOUT: {
            SendFRAMEPacket((unsigned char *) &frameBuffer[exceptFrame].head, frameBuffer[exceptFrame].size);
            break;
        }
    }
}

/*
* 回退n帧测试函数
*/
int stud_slide_window_back_n_frame(char *pBuffer, int bufferSize, UINT8 messageType) {
    switch (messageType) {
        case MSG_TYPE_SEND: {
            printf("SEND:\n");
            frameBuffer[lastFrame].head = *(frame_head *) pBuffer; //缓存
            frameBuffer[lastFrame].size = bufferSize;
            lastFrame++;
            if (lastFrame - exceptFrame <= WINDOW_SIZE_BACK_N_FRAME) {
                SendFRAMEPacket((unsigned char *) pBuffer, (unsigned int) bufferSize);
                printf("%d\n\n", nextFrame);
                nextFrame++;
            }
            break;
        }
        case MSG_TYPE_RECEIVE: {
            printf("RECEIVE:\n");
            unsigned int ack = ntohl(((frame_head *) pBuffer)->ack);
            printf("ack:%d\n", ack);
            for (int i = exceptFrame; i < lastFrame; i++) {
                unsigned int exceptAck = ntohl(frameBuffer[i].head.seq);
                printf("ack:%d\n", exceptAck);
                if (exceptAck <= ack) {
                    exceptFrame++;
                    if (nextFrame < lastFrame) {
                        SendFRAMEPacket((unsigned char *) &frameBuffer[nextFrame].head,
                                        (unsigned int) frameBuffer[nextFrame].size);
                        printf("%d\n\n", nextFrame);
                        nextFrame++;
                    }
                }
            }
            break;
        }
        case MSG_TYPE_TIMEOUT: {
            printf("TIMEOUT:\n");
            for (int i = exceptFrame; i < nextFrame; i++) {
                SendFRAMEPacket((unsigned char *) &frameBuffer[i].head, (unsigned int) frameBuffer[i].size);
                printf("%d\n\n", i);
            }
            break;
        }
    }
}

/*
* 选择性重传测试函数
*/
int stud_slide_window_choice_frame_resend(char *pBuffer, int bufferSize, UINT8 messageType) {
    switch (messageType) {
        case MSG_TYPE_SEND: {
            printf("SEND:\n");
            frameBuffer[lastFrame].head = *(frame_head *) pBuffer; //缓存
            frameBuffer[lastFrame].size = bufferSize;
            lastFrame++;
            if (lastFrame - exceptFrame <= WINDOW_SIZE_BACK_N_FRAME) {
                SendFRAMEPacket((unsigned char *) pBuffer, (unsigned int) bufferSize);
                printf("%d\n\n", nextFrame);
                nextFrame++;
            }
            break;
        }
        case MSG_TYPE_RECEIVE: {
            printf("RECEIVE:\n");
            unsigned int type = ntohl(((frame_head *) pBuffer)->kind);
            unsigned int ackN = ntohl(((frame_head *) pBuffer)->ack);
            if (type == ack) {
                printf("ack:%d\n", ackN);
                for (int i = exceptFrame; i < lastFrame; i++) {
                    unsigned int exceptAck = ntohl(frameBuffer[i].head.seq);
                    printf("ack:%d\n", exceptAck);
                    if (exceptAck <= ackN) {
                        exceptFrame++;
                        if (nextFrame < lastFrame) {
                            SendFRAMEPacket((unsigned char *) &frameBuffer[nextFrame].head,
                                            (unsigned int) frameBuffer[nextFrame].size);
                            printf("%d\n\n", nextFrame);
                            nextFrame++;
                        }
                    }
                }
            }
            if (type == nak) {
                for (int i = exceptFrame; i < nextFrame; i++) {
                    unsigned int exceptAck = ntohl(frameBuffer[i].head.seq);
                    if (exceptAck == ackN) {
                        SendFRAMEPacket((unsigned char *) &frameBuffer[i].head,
                                        (unsigned int) frameBuffer[i].size);
                        break;
                    }
                }
            }
            break;
        }
        case MSG_TYPE_TIMEOUT: {
            printf("TIMEOUT:\n");
            for (int i = exceptFrame; i < nextFrame; i++) {
                SendFRAMEPacket((unsigned char *) &frameBuffer[i].head, (unsigned int) frameBuffer[i].size);
                printf("%d\n\n", i);
            }
            break;
        }
    }
}
最后修改:2020 年 10 月 11 日
如果觉得我的文章对你有用,请随意赞赏