数据链路层选择重传协议不同于停等协议和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()函数的具体实现
主函数实现