模仿数据链路层的gobackn协议 /*该协议是搭载ack的回退n步协议*/ #include <stdio.h> #include "protocol.h" #define max_seq 7 #define flag 126 #define ESC 100 #define wait_time 2700 //发送计时器等待的时间 #define ack_wait_time 280 static int phl_ready = 0; unsigned char buf[max_seq+1][270]; unsigned char ack[8]; //发送空的ack帧 unsigned char in_buf[600], last_buf[520];//接收时的缓冲区;去掉冗余之后的缓冲区,为防备因误码两帧合并为一帧而定义了很大一个数组 int nbuffered=0; //发送的帧数 int buf_size[max_seq+1]; //记下以发送各帧的帧长 int next_frame_to_send=0; int frame_in_phl=0; //用于成帧 int frame_expected=0; int ack_expected=0; int between(int a,int b,int c) { if( ((a<=b)&&(b<c)) || ((c<a)&&(a<=b)) || ((b<c)&&(c<a)) ) return 1; else return 0; } //判断帧尾,防止出现误判esc esc flag为数据的情况 int end_flag(int in_len) { int count=0; int i; if(in_len<=0) return 1; for(i=in_len-1;in_buf[i]==ESC&&i>=0;i--)//记录flag前的esc数目 count++; return count%2; //若flag前的esc为偶数,则为帧尾 }//成帧函数--数据帧 void send_frame(char *my_buf,int len) { int n; buf[frame_in_phl][0]=(frame_expected+max_seq)%(max_seq+1); //ack buf[frame_in_phl][1]=frame_in_phl; //发送帧的帧号 for(n=0;n<len;n++) buf[frame_in_phl][n+2]=my_buf[n]; //将处理过的新帧赋值到缓冲区中 len=len+2; *(unsigned int *)(buf[frame_in_phl]+len) = crc32(buf[frame_in_phl],len); //在原始帧的基础上加检验和 buf_size[frame_in_phl]=len+4; //记录当前帧的长度,包括3个帧头,4个检验和 nbuffered=nbuffered+1; //缓冲区占用数加一 frame_in_phl=(frame_in_phl+1)%(max_seq+1); } //成帧函数--ack帧 void send_ack() //ack帧的处理 { ack[0]=(frame_expected+max_seq)%(max_seq+1); ack[1]=max_seq+10; //ack帧的序号位,使ack[1]==frame_expected恒不成立 *(unsigned int *)(ack+2) = crc32(ack,2); //在原始帧的基础上加检验和 } //主函数 int main(int argc, char **argv) { int event, arg, n , m , i , j , len = 0 ,in_len = 0; unsigned char my_buf[260]; int phl_wait=0; //在物理层中还没有被发送的帧 protocol_init(argc, argv); enable_network_layer(); for (;;) { event = wait_for_event(&arg); switch (event) { case NETWORK_LAYER_READY: len = get_packet(my_buf); phl_wait++; send_frame(my_buf,len); stop_ack_timer(); if (phl_ready) { for(j=0;j<phl_wait;j++) { //帧结构为 ack seq 内容 //每帧尾部加发送一个flag for (i = 0; i < buf_size[next_frame_to_send]; i++){ if ((buf[next_frame_to_send][i]==flag) || (buf[next_frame_to_send][i]==ESC) ) send_byte(ESC); send_byte(buf[next_frame_to_send][i]); } send_byte(flag);//帧尾 start_timer(next_frame_to_send,wait_time); //发送完启动相应的定时器 next_frame_to_send=(next_frame_to_send+1)%(max_seq+1); } phl_ready = 0; //记录物理层当前状态为 phl_wait = phl_wait-j; } break; case PHYSICAL_LAYER_READY: if (phl_wait) { //若有未发送的帧,便发送 for(j=0;j<phl_wait;j++) { for (i = 0; i < buf_size[next_frame_to_send]; i++){ if ( (buf[next_frame_to_send][i]==flag) || (buf[next_frame_to_send][i]==ESC) ) send_byte(ESC); send_byte(buf[next_frame_to_send][i]); } send_byte(flag); //帧尾 start_timer(next_frame_to_send,wait_time); //发送完启动相应的定时器 next_frame_to_send=(next_frame_to_send+1)%(max_seq+1); } phl_ready = 0; //物理层当前状态 phl_wait=phl_wait-j; } else phl_ready = 1; //物理层状态可用 break; case DATA_INCOMING: for (i=0; i < arg; i++, in_len++) //挨个字节处理 { in_buf[in_len] = recv_byte(); if(in_len>0&&(end_flag(in_len)==0)&&in_buf[in_len]==flag) { //判断帧尾 for(m=0,j=0;m<in_len;m++,j++){ //删掉所有的esc if(in_buf[m]==ESC) m++; last_buf[j]=in_buf[m]; } if( crc32(last_buf,j)==0 ) //检验收到的帧是否有误码 { while(between(ack_expected,last_buf[0],next_frame_to_send)) { //回馈的ack大于ack_expected,则所有帧都被确认 //log_printf("receive an ack %d ;",last_buf[0]); --nbuffered; stop_timer(ack_expected); //停止相应的定时器 ack_expected=(ack_expected+1)%(max_seq+1); }//end while if(last_buf[1]==frame_expected) { // log_printf("receive a frame %d of %d bytes ;",last_buf[1], last_buf[2]+1); put_packet(&last_buf[2],j-6); //减去帧头和检验和 stop_ack_timer(); start_ack_timer(ack_wait_time); frame_expected=(frame_expected+1)%(max_seq+1); }//end if }//end if //else log_printf("****Wrong Frame!!!***%d %d %d %d\n",in_buf[0],last_buf[0],last_buf[1],in_buf[in_len]); in_len=-1; //in_len变为-1,为重新接受新帧做准备 }//end if }//end for phl_sq_len(); break; case ACK_TIMEOUT: if(phl_ready) { send_ack(); //调用函数成ack帧 //log_printf("Ack %d Sent!!!\n", ack[0]); for (i = 0; i < 7; i++){ //发送ack缓冲区里的字节 if(ack[i]==ESC || ack[i]==flag) send_byte(ESC); send_byte(ack[i]); } send_byte(flag); phl_ready = 0; } break; case DATA_TIMEOUT://这儿需要重新成帧,直接在段里实现(待完成) //将存在缓冲区中的帧所带的ack更新!!! //log_printf("***%d timer overflow ***\n",ack_expected); next_frame_to_send=ack_expected; //重发 if(phl_ready){ stop_ack_timer(); //停止ack定时器 for(i=1;i<=nbuffered;i++){ if(buf[next_frame_to_send][0]!=(frame_expected+max_seq)%(max_seq+1)) { //更新ack buf[next_frame_to_send][0]=(frame_expected+max_seq)%(max_seq+1); *(unsigned int *)(buf[next_frame_to_send]+(buf_size[next_frame_to_send]-4)) = crc32(buf[next_frame_to_send],(buf_size[next_frame_to_send]-4)); } //send_byte(flag); for(n=0 ; n<buf_size[next_frame_to_send] ; n++){ if(buf[next_frame_to_send][n]==ESC || buf[next_frame_to_send][n]==flag) send_byte(ESC); send_byte(buf[next_frame_to_send][n]); //发送帧内容 } send_byte(flag); //发送帧尾 start_timer(next_frame_to_send,wait_time); //启动定时器 next_frame_to_send=(next_frame_to_send+1)%(max_seq+1); } phl_ready = 0; } else phl_wait=nbuffered; //若物理层不可用,标记为phl_wait break; } if (nbuffered < max_seq) enable_network_layer(); else disable_network_layer(); } }
- 1
- 粉丝: 1
- 资源: 1
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 计算机专业前端React入门开发一个小应用教程
- 新能源汽车车载双向OBC,PFC,LLC,V2G 双向 充电桩 电动汽车 车载充电机 充放电机 MATLAB仿真模型 (1)基于V2G技术的双向AC DC、DC DC充放电机MATLAB仿真模型; (
- 图像分割数据集:房屋建筑图像语义分割数据集(21类分割,约400张数据和标签)
- LED恒流驱动器Hi600X系列高精度调光及应用详解
- 安全隐患自查表.docx
- “私车公养”问题自查自纠表.docx
- 变压器损耗对照表.docx
- 部门年度绩效自评工作报告(参考提纲).docx
- 创客人才基础人才购房补贴申请表.doc
- 创客人才基础人才购房优惠资格认定表.doc
- 创新型领军和拔尖人才购房安家补助申请表.doc
- 大型医院巡查工作方案(2025-2026年度).docx
- 单位内设机构领导职数情况对照表.doc
- 电力变压器损耗及损失电量速算表.docx
- 独生子女户、农村纯二女结扎户子女审核确认花名册.wps
- 发放劳务费明细表.docx
评论13