用c语言写数据链路层选择重传协议

时间:2024-03-27 21:56:55

数据链路层选择重传协议不同于停等协议和go-backn,选择重传协议是接收方窗口是固定大小为(MAX_SEQ+1)/2

发送方窗口是0--(MAX_SEQ+1)/2,采用捎带确认,而且加入NAK,分别有两个计时器,ACK定时器和数据定时器

话不多说   上代码!!!!

#include <stdio.h>
#include <string.h>

#include "protocol.h"
#include "datalink.h"

#define DATA_TIMER  3000  //数据计时器
#define ACK_TIMER 1000            //ACK计时器
#define MAX_SEQ 31
#define NR_BUFS ((MAX_SEQ+1)/2)

typedef enum { false, true }boolean;//布尔变量
struct FRAME {
    unsigned char kind; // FRAME_DATA ,FRAME_NAK ,FRAME_ACK
    unsigned char ack;
    unsigned char seq;
    unsigned char data[PKT_LEN];
    unsigned int  padding;
};

boolean arrive[NR_BUFS];//标记接收缓冲区是否被占用
int no_nak = 1;//没有nak发送
static unsigned char  nbuffered = 0;//当前发送缓存数目
static unsigned char in_buffer[NR_BUFS][PKT_LEN], out_buffer[NR_BUFS][PKT_LEN];//接收,发送缓存
static int phl_ready = 0;//表示物理层没就绪
static unsigned char ack_expected = 0, next_frame_to_send = 0;//发送窗口下界和上界
static unsigned char  frame_expected = 0, too_far = NR_BUFS;//接收窗口下界和上界

static int between(unsigned char a, unsigned char b, unsigned char c)
{
    return (((a <= b) && (b < c)) || ((c < a) && (a <= b)) || ((b < c) && (c < a)));
}

static void put_frame(unsigned char *frame, int len)
{
    *(unsigned int *)(frame + len) = crc32(frame, len);
    send_frame(frame, len + 4);
    phl_ready = 0;
}

static void send_data_frame(unsigned char F_kind, unsigned char frame_nr)//发送包的函数,可能是DATA 或ACK 或NAK
{
    struct FRAME s;

    s.kind = F_kind;
    s.seq = frame_nr;
    s.ack = (frame_expected + MAX_SEQ) % (MAX_SEQ + 1);
    switch (F_kind)
    {
    case FRAME_DATA:
    {
        for (int i = 0; i < PKT_LEN; i++)
            s.data[i] = out_buffer[frame_nr%NR_BUFS][i];


        dbg_frame("Send DATA %d %d, ID %d\n", s.seq, s.ack, *(short *)s.data);

        put_frame((unsigned char *)&s, 3 + PKT_LEN);//CRC已经加完  并且已经向物理层发送一帧
        start_timer(frame_nr % NR_BUFS, DATA_TIMER);
    }break;
    case FRAME_ACK:
    {
        dbg_frame("Send ACK %d\n", s.ack);
        put_frame((unsigned char *)&s, 2);

    }break;
    case FRAME_NAK:
    {
        no_nak = 0;
        dbg_frame("Send NAK %d\n", s.ack);
        put_frame((unsigned char *)&s, 2);//2NAK+4CRC+1SEQ
    }break;
    }
    //phl_ready = 0;//////// 只是一帧的发送需要准备好  同时在流量控制也有用
    stop_ack_timer();////////////发送数据时候就把ACK定时器给关闭
}


int main(int argc, char **argv)
{
    int event, arg;
    struct FRAME f;
    int len = 0;
    for (int i = 0; i < NR_BUFS; i++)
        arrive[i] = false;
    protocol_init(argc, argv);
    lprintf("Designed by Panrixin, build: " __DATE__"  "__TIME__"\n");

    enable_network_layer();

    for (;;)
    {
        event = wait_for_event(&arg);

        switch (event)
        {
        case NETWORK_LAYER_READY://网络层准备好
        {
            dbg_event("Nerwork layer ready:\n");
            get_packet(out_buffer[next_frame_to_send % NR_BUFS]);//从网络层拿包
            nbuffered++;//缓存+1
            send_data_frame(FRAME_DATA, next_frame_to_send);//发包
            next_frame_to_send++;
            next_frame_to_send = next_frame_to_send % (MAX_SEQ + 1);
            break;
        }
        case PHYSICAL_LAYER_READY://物理层 准备好
        {
            dbg_event("Physical layer ready:\n");
            phl_ready = 1;//更改状态
            break;
        }
        case FRAME_RECEIVED://收到一个包
        {
            dbg_event("Frame had received:\n");
            len = recv_frame((unsigned char *)&f, sizeof f);//检测CRC
            if (len < 5 || crc32((unsigned char *)&f, len) != 0)
            {
                dbg_event("**** Receiver Error, Bad CRC Checksum\n");
                if (no_nak)
                    send_data_frame(FRAME_NAK, 0);
                break;
            }
            
            if (f.kind == FRAME_DATA)
            {
                dbg_frame("Recv DATA %d %d, ID %d\n", f.seq, f.ack, *(short *)f.data);
                if (f.seq != frame_expected && no_nak)//序号不对而且还没发NAK
                {
                    send_data_frame(FRAME_NAK, 0);
                }
                else
                    start_ack_timer(ACK_TIMER);//启动ACK定时器
                if (between(frame_expected, f.seq, too_far) && (arrive[f.seq % NR_BUFS]) == false)//包正确
                {
                    arrive[f.seq % NR_BUFS] = true;//标记状态要更改
                    for (int i = 0; i < len - 7; i++)
                        in_buffer[f.seq % NR_BUFS][i] = f.data[i];//放到接收缓冲区
                    while (arrive[frame_expected%NR_BUFS])//对有标记状态的包递交网络层,按顺序!!!
                    {
                        put_packet(in_buffer[frame_expected%NR_BUFS], len - 7);
                        no_nak = true;
                        arrive[frame_expected%NR_BUFS] = false;
                        frame_expected++;
                        frame_expected %= (MAX_SEQ + 1);
                        too_far++;
                        too_far %= (MAX_SEQ + 1);
                        start_ack_timer(ACK_TIMER);
                    }
                }
            }

            if (f.kind == FRAME_NAK && between(ack_expected, (f.ack + 1) % (MAX_SEQ + 1), next_frame_to_send))
            {
                dbg_frame("Recv NAK  %d\n", f.ack);
                send_data_frame(FRAME_DATA, (f.ack + 1) % (MAX_SEQ + 1));//收到NAK,重发对应该帧
            }
            ///////////////////////break;
            while (between(ack_expected, f.ack, next_frame_to_send))//收到ACK  停止包计时器
            {
                nbuffered--;
                stop_timer(ack_expected % NR_BUFS);
                ack_expected++;
                ack_expected %= (MAX_SEQ + 1);
            }
            break;
        }
        case DATA_TIMEOUT://超时  需要重传
        {
            dbg_event("---- DATA %d timeout\n", arg);
            send_data_frame(FRAME_DATA, ack_expected);
            break;
        }
        case ACK_TIMEOUT://ack超时  重新发送ACK
        {
            dbg_event("ACK %d timeout\n", arg);
            send_data_frame(FRAME_ACK, 0);
            break;
        }
        }

        if (nbuffered < NR_BUFS && phl_ready)//确定好物理层状态在产生事件
            enable_network_layer();
        else
            disable_network_layer();
    }
}
代码中都有注释,很详细,但是这个程序需要有很多其他的文件才能运行,说白了这只是工程中的一个程序,但是由于某些原因不能发出来,谁如果想要的话私信我哈!

send_data_frame()函数的具体实现

用c语言写数据链路层选择重传协议

 

主函数实现

用c语言写数据链路层选择重传协议