文章目录

  • 前引
  • Lab1 实现可靠的传输协议
    • Lab1 文档查阅(友情提供下载链接)
    • 查看c语言参数声明的说明
    • 原模版代码(个人整理格式后)
    • 原模板代码(稍加分析)
    • 交替位协议版本 代码实现
    • 交替位协议版本 实现效果

前引


各位好 我写到这里其实我也还是挺意外的 因为其实我是想在CS144中再手撕TCP的 但是没想到《计算机自顶向下》里面居然有这个小实验 那既然有 哪里有不做的道理 反正CS144的实验也是迟早要完成的

我的预计本来是把Socket编程+Wireshark实验+CS144完成了 配套着《计算机自顶向下》+之前快速看完的哈工大课程 我们就愉快的完成计算机网络的学习 哈哈哈 但是其实发现要完成的还是相当多的


Lab1 实现可靠的传输协议


Lab1 文档查阅(友情提供下载链接)


方便大家下载相关文档 下面是查阅链接
Programming Assignment 5: Implementing a Reliable Transport Protocol
prog2.c代码

下面是查阅的文档截图 详细的大家还是点进去仔细看看吧 这里我用的是谷歌的自带翻译 所以查阅起来比较方便阅读


我们大概要完成的任务就是下图中的从A->B的信息传递 只需要完成单向的 哈哈 不是说单项的B就不向A传递信息了 B如果不向A握手那还怎么连接呢


文档中指示了我们需要完成下面五个函数
A_output(message),其中message是一个msg类型的结构体 ,包含要发送到B端的数据。每当发送端 (A) 的上层有消息要发送时,就会调用此例程。您的协议的工作是确保此类消息中的数据按顺序正确传递到接收方上层。

A_input(packet),其中packet是pkt类型的结构体 。每当从 B 端发送的数据包(即,作为B 端过程执行的tolayer3()的结果)到达 A 端时,将调用该例程。数据包是从 B 端发送的(可能已损坏的)数据包。

A_timerinterrupt() 当 A 的定时器超时(从而产生定时器中断)时,将调用该例程。您可能希望使用此例程来控制数据包的重新传输。请参阅下面的starttimer() 和stoptimer()以了解计时器的启动和停止方式。

A_init()在调用任何其他 A 端例程之前,该例程将被调用一次。它可用于执行任何所需的初始化。

B_input(packet),其中packet是pkt类型的结构体 。每当从 A 端发送的数据包(即,作为A 端过程执行的tolayer3()的结果)到达 B 端时,将调用该例程。数据包是从 A 端发送的(可能已损坏的)数据包。

B_init()在调用任何其他 B 端例程之前,该例程将被调用一次。它可用于执行任何所需的初始化。


查看c语言参数声明的说明


我刚刚在查看官方文档的时候 看到了下面的c语言参数代码让我百思不得其解 因为我实在没看到过这样子的声明

这个是什么啊 我是真的这样想的 第一个既没有返回值 参数还是这样设置的 第二个是int AorB char datasent[20]

tolayer5(AorB,datasent)int AorB;char datasent[20];
{int i;  if (TRACE>2) {printf("          TOLAYER5: data received: ");for (i=0; i<20; i++)  printf("%c",datasent[i]);printf("\n");}
}

之后我试了一下 函数如下 如果没有返回值的话 默认为return 0

#include <stdio.h>f(a)
int a;
{printf("nono\n");
}main()
{int a = f(a);printf("goog %d\n",a);return;
}


原模版代码(个人整理格式后)


尽管不得不说 这个网络模拟器和调试的地方 确实提供模板的老师写的很好 但是不得不说 确实太乱了 - - 乱到很多时候 我读代码都不忍直视 读都读不下去 实在是受不了了

于是在大概花了个5-6分钟左右 我把格式做了优化 看起来也整洁很多

#include <stdio.h>/* ******************************************************************ALTERNATING BIT AND GO-BACK-N NETWORK EMULATOR: VERSION 1.1  J.F.KuroseThis code should be used for PA2, unidirectional or bidirectionaldata transfer protocols (from A to B. Bidirectional transfer of datais for extra credit and is not required).  Network properties:- one way network delay averages five time units (longer if thereare other messages in the channel for GBN), but can be larger- packets can be corrupted (either the header or the data portion)or lost, according to user-defined probabilities- packets will be delivered in the order in which they were sent(although some can be lost).
**********************************************************************/#define BIDIRECTIONAL 0    /* change to 1 if you're doing extra credit *//* and write a routine called B_output *//* a "msg" is the data unit passed from layer 5 (teachers code) to layer  */
/* 4 (students' code).  It contains the data (characters) to be delivered */
/* to layer 5 via the students transport level protocol entities.         */
struct msg
{char data[20];
};/* a packet is the data unit passed from layer 4 (students code) to layer */
/* 3 (teachers code).  Note the pre-defined packet structure, which all   */
/* students must follow. */
struct pkt
{int seqnum;int acknum;int checksum;char payload[20];
};/********* STUDENTS WRITE THE NEXT SEVEN ROUTINES *********/
#define send_cnts_MAX 3
#define send_time_MAX  6struct msg A_msg;
int A_sendcnts;
float A_sendtime;/* called from layer 5, passed the data to be sent to other side */
A_output(message)struct msg message;
{starttimerr(A,A_sendtime);
}B_output(message)  /* need be completed only for extra credit */struct msg message;
{}/* called from layer 3, when a packet arrives for layer 4 */
A_input(packet)struct pkt packet;
{}/* called when A's timer goes off */
A_timerinterrupt()
{}/* the following routine will be called once (only) before any other */
/* entity A routines are called. You can use it to do any initialization */
A_init()
{int i;for(i=0;i<20;++i)A_msg[i] = '\0';A_sendcnts = 0;A_sendtime = 0;
}/* Note that with simplex transfer from a-to-B, there is no B_output() *//* called from layer 3, when a packet arrives for layer 4 at B*/
B_input(packet)struct pkt packet;
{}/* called when B's timer goes off */
B_timerinterrupt()
{}/* the following rouytine will be called once (only) before any other */
/* entity B routines are called. You can use it to do any initialization */
B_init()
{}/*****************************************************************
***************** NETWORK EMULATION CODE STARTS BELOW ***********
The code below emulates the layer 3 and below network environment:- emulates the tranmission and delivery (possibly with bit-level corruptionand packet loss) of packets across the layer 3/4 interface- handles the starting/stopping of a timer, and generates timerinterrupts (resulting in calling students timer handler).- generates message to be sent (passed from later 5 to 4)THERE IS NOT REASON THAT ANY STUDENT SHOULD HAVE TO READ OR UNDERSTAND
THE CODE BELOW.  YOU SHOLD NOT TOUCH, OR REFERENCE (in your code) ANY
OF THE DATA STRUCTURES BELOW.  If you're interested in how I designed
the emulator, you're welcome to look at the code - but again, you should have
to, and you defeinitely should not have to modify
******************************************************************/struct event {float evtime;           /* event time */int evtype;             /* event type code */int eventity;           /* entity where event occurs */struct pkt *pktptr;     /* ptr to packet (if any) assoc w/ this event */struct event *prev;struct event *next;};
struct event *evlist = NULL;   /* the event list *//* possible events: */int TRACE = 1;             /* for my debugging */
int nsim = 0;              /* number of messages from 5 to 4 so far */
int nsimmax = 0;           /* number of msgs to generate, then stop */
float time = 0.000;
float lossprob;            /* probability that a packet is dropped  */
float corruptprob;         /* probability that one bit is packet is flipped */
float lambda;              /* arrival rate of messages from layer 5 */
int   ntolayer3;           /* number sent into layer 3 */
int   nlost;               /* number lost in media */
int ncorrupt;              /* number corrupted by media*/main()
{struct event *eventptr;struct msg  msg2give;struct pkt  pkt2give;int i,j;char c;init();A_init();B_init();while (1){eventptr = evlist;            /* get next event to simulate */if (eventptr==NULL)goto terminate;evlist = evlist->next;        /* remove this event from event list */if (evlist!=NULL)evlist->prev=NULL;if (TRACE>=2){printf("\nEVENT time: %f,",eventptr->evtime);printf("  type: %d",eventptr->evtype);if (eventptr->evtype==0)printf(", timerinterrupt  ");else if (eventptr->evtype==1)printf(", fromlayer5 ");elseprintf(", fromlayer3 ");printf(" entity: %d\n",eventptr->eventity);}time = eventptr->evtime;        /* update time to next event time */if (nsim==nsimmax)break;                        /* all done with simulation */if (eventptr->evtype == FROM_LAYER5){generate_next_arrival();   /* set up future arrival *//* fill in msg to give with string of same letter */j = nsim % 26;for (i=0; i<20; i++)msg2give.data[i] = 97 + j;if (TRACE>2){printf("          MAINLOOP: data given to student: ");for (i=0; i<20; i++)printf("%c", msg2give.data[i]);printf("\n");}nsim++;if (eventptr->eventity == A)A_output(msg2give);elseB_output(msg2give);}else if (eventptr->evtype ==  FROM_LAYER3){pkt2give.seqnum = eventptr->pktptr->seqnum;pkt2give.acknum = eventptr->pktptr->acknum;pkt2give.checksum = eventptr->pktptr->checksum;for (i=0; i<20; i++)pkt2give.payload[i] = eventptr->pktptr->payload[i];if (eventptr->eventity ==A)      /* deliver packet by calling */A_input(pkt2give);            /* appropriate entity */elseB_input(pkt2give);free(eventptr->pktptr);          /* free the memory for packet */}else if (eventptr->evtype ==  TIMER_INTERRUPT){if (eventptr->eventity == A)A_timerinterrupt();elseB_timerinterrupt();}else    printf("INTERNAL PANIC: unknown event type \n");free(eventptr);}terminate:printf(" Simulator terminated at time %f\n after sending %d msgs from layer5\n",time,nsim);
}init()                         /* initialize the simulator */
{int i;float sum, avg;float jimsrand();printf("-----  Stop and Wait Network Simulator Version 1.1 -------- \n\n");printf("Enter the number of messages to simulate: ");scanf("%d",&nsimmax);       // 发送数据包数目printf("Enter packet loss probability [enter 0.0 for no loss]:");scanf("%f",&lossprob);      // 丢包率printf("Enter packet corruption probability [0.0 for no corruption]:");scanf("%f",&corruptprob);   // 包损坏率printf("Enter average time between messages from sender's layer5 [ > 0.0]:");scanf("%f",&lambda);        // 平均物理层传输时间printf("Enter TRACE:");scanf("%d",&TRACE);         // 追踪 用于调试的srand(9999);              /* init random number generator */sum = 0.0;                /* test random number generator for students */for (i=0; i<1000; i++)sum=sum+jimsrand();    /* jimsrand() should be uniform in [0,1] */avg = sum/1000.0;         // 随机概率 估计值在0.25 ~ 0.75if (avg < 0.25 || avg > 0.75){printf("It is likely that random number generation on your machine\n" );printf("is different from what this emulator expects.  Please take\n");printf("a look at the routine jimsrand() in the emulator code. Sorry. \n");exit(0);}ntolayer3 = 0;nlost = 0;ncorrupt = 0;time=0.0;                    /* initialize time to 0.0 */generate_next_arrival();     /* initialize event list */
}/****************************************************************************/
/* jimsrand(): return a float in range [0,1].  The routine below is used to */
/* isolate all random number generation in one location.  We assume that the*/
/* system-supplied rand() function return an int in therange [0,mmm]        */
/****************************************************************************/float jimsrand()
{double mmm = 2147483647;   /* largest int  - MACHINE DEPENDENT!!!!!!!!   */float x;                   /* individual students may need to change mmm */x = rand()/mmm;            /* x should be uniform in [0,1] */return(x);
}/********************* EVENT HANDLINE ROUTINES *******/
/*  The next set of routines handle the event list   */
/*****************************************************/generate_next_arrival()
{double x,log(),ceil();struct event *evptr;char *malloc();float ttime;int tempint;if (TRACE>2)printf("          GENERATE NEXT ARRIVAL: creating new arrival\n");x = lambda*jimsrand()*2;  /* x is uniform on [0,2*lambda] *//* having mean of lambda        */evptr = (struct event *)malloc(sizeof(struct event));evptr->evtime =  time + x;evptr->evtype =  FROM_LAYER5;if (BIDIRECTIONAL && (jimsrand()>0.5) )evptr->eventity = B;elseevptr->eventity = A;insertevent(evptr);
}// 由之前生成的包中的eventtime决定 传输顺序 在队列中的什么位置
insertevent(p)struct event *p;
{struct event *q,*qold;if (TRACE>2){printf("            INSERTEVENT: time is %lf\n",time);printf("            INSERTEVENT: future time will be %lf\n",p->evtime);}q = evlist;     /* q points to header of list in which p struct inserted */if (q==NULL)    /* list is empty */{evlist=p;p->next=NULL;p->prev=NULL;}else{for (qold = q; q !=NULL && p->evtime > q->evtime; q=q->next)qold=q;if (q==NULL)    /* end of list */{qold->next = p;p->prev = qold;p->next = NULL;}else if (q==evlist) /* front of list */{p->next=evlist;p->prev=NULL;p->next->prev=p;evlist = p;}else            /* middle of list */{p->next=q;p->prev=q->prev;q->prev->next=p;q->prev=p;}}
}printevlist()
{struct event *q;int i;printf("--------------\nEvent List Follows:\n");for(q = evlist; q!=NULL; q=q->next)printf("Event time: %f, type: %d entity: %d\n",q->evtime,q->evtype,q->eventity);printf("--------------\n");
}/********************** Student-callable ROUTINES ***********************//* called by students routine to cancel a previously-started timer */
stoptimer(AorB)int AorB;  /* A or B is trying to stop timer */
{struct event *q,*qold;if (TRACE>2)printf("          STOP TIMER: stopping timer at %f\n",time);/* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next)  */for (q=evlist; q!=NULL ; q = q->next){/* remove this event */if ( (q->evtype==TIMER_INTERRUPT  && q->eventity==AorB) ){if (q->next==NULL && q->prev==NULL)evlist=NULL;         /* remove first and only event on list */else if (q->next==NULL) /* end of list - there is one in front */q->prev->next = NULL;else if (q==evlist)     /* front of list - there must be event after */{q->next->prev=NULL;evlist = q->next;}else    /* middle of list */{q->next->prev = q->prev;q->prev->next =  q->next;}free(q);return;}}printf("Warning: unable to cancel your timer. It wasn't running.\n");
}starttimer(AorB,increment)int AorB;  /* A or B is trying to stop timer */float increment;
{struct event *q;struct event *evptr;char *malloc();if (TRACE>2)printf("          START TIMER: starting timer at %f\n",time);/* be nice: check to see if timer is already started, if so, then  warn *//* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next)  */for (q=evlist; q!=NULL ; q = q->next){if (q->evtype==TIMER_INTERRUPT  && q->eventity==AorB ){printf("Warning: attempt to start a timer that is already started\n");return;}}/* create future event for when timer goes off */evptr = (struct event *)malloc(sizeof(struct event));evptr->evtime =  time + increment;evptr->evtype =  TIMER_INTERRUPT;evptr->eventity = AorB;insertevent(evptr);
}/************************** TOLAYER3 ***************/
tolayer3(AorB,packet)int AorB;  /* A or B is trying to stop timer */
struct pkt packet;
{struct pkt *mypktptr;struct event *evptr,*q;char *malloc();float lastime, x, jimsrand();int i;ntolayer3++;/* simulate losses: */if (jimsrand() < lossprob){nlost++;if (TRACE>0)printf("          TOLAYER3: packet being lost\n");return;}/* make a copy of the packet student just gave me since he/she may decide */
/* to do something with the packet after we return back to him/her */mypktptr = (struct pkt *)malloc(sizeof(struct pkt));mypktptr->seqnum = packet.seqnum;mypktptr->acknum = packet.acknum;mypktptr->checksum = packet.checksum;for (i=0; i<20; i++)mypktptr->payload[i] = packet.payload[i];if (TRACE>2){printf("          TOLAYER3: seq: %d, ack %d, check: %d ", mypktptr->seqnum,mypktptr->acknum,  mypktptr->checksum);for (i=0; i<20; i++)printf("%c",mypktptr->payload[i]);printf("\n");}/* create future event for arrival of packet at the other side */evptr = (struct event *)malloc(sizeof(struct event));evptr->evtype =  FROM_LAYER3;   /* packet will pop out from layer3 */evptr->eventity = (AorB+1) % 2; /* event occurs at other entity */evptr->pktptr = mypktptr;       /* save ptr to my copy of packet *//* finally, compute the arrival time of packet at the other end.medium can not reorder, so make sure packet arrives between 1 and 10time units after the latest arrival time of packetscurrently in the medium on their way to the destination */lastime = time;/* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */for (q=evlist; q!=NULL ; q = q->next){if ( (q->evtype==FROM_LAYER3  && q->eventity==evptr->eventity) )lastime = q->evtime;}evptr->evtime =  lastime + 1 + 9*jimsrand();/* simulate corruption: */if (jimsrand() < corruptprob){ncorrupt++;if ( (x = jimsrand()) < .75)mypktptr->payload[0]='Z';   /* corrupt payload */else if (x < .875)mypktptr->seqnum = 999999;elsemypktptr->acknum = 999999;if (TRACE>0)printf("          TOLAYER3: packet being corrupted\n");}if (TRACE>2)printf("          TOLAYER3: scheduling arrival on other side\n");insertevent(evptr);
}tolayer5(AorB,datasent)int AorB;char datasent[20];
{int i;if (TRACE>2){printf("          TOLAYER5: data received: ");for (i=0; i<20; i++)printf("%c",datasent[i]);printf("\n");}
}

原模板代码(稍加分析)


有什么说什么 做这个Lab的老师写的代码也太不规范了吧
不知道是不是年代很久以前? 还是怎么样 我光理解很多地方都理解了很久 - - 真的很看不懂一些地方的赋值 初始化 命名方式

真的很想改一些地方的 但是源于感谢这个Lab老师编写的代码 还有老师在代码的注释行专门强调了 不允许修改下面的代码 既然这样 源于尊重和理解 我们就不改了

但是最后还是改了 因为一些需求
首先我想用累积确认 还有仅用ACK确认最后一次已经收到的包 这样的话就可以不用ACK和NAK了 我是想先把交替位协议版本给做了 再做有流水线的GBN滑动窗口 反正刚开始它让我们要用NAK 和 ACK 我就用了 之后的话 对于GBN我再改吧

对了 这里我实现的仅实现了单边的交流 没有实现双边的- - 能力有限 对于双边的或者更好的 就留在CS144那里来弄吧

对于刚开始拿到这个代码的hxd来说 确实挺难的 因为各个地方都没有思路 这里的话 我对每个代码块做一个小说明吧 因为基本上代码我都是看完了再来写的

A_output(message) A的应用层到传输层 Layer5->Layer3 协议包装msg包装成数据包packet
A_input(packet) A的传输层处理数据包 对于坏包或者检测错误 用于处理 不需要回传给应用层
A_timerinterrupt() A的计时器 如果超时的话 则进入A_timerinterrupt处理 进入函数处理由一个队列(老师自己做的模拟器 后面会写)自动处理
A_init() 最开始的初始化 我初始化的很少 处理了一些全局变量
B_init() 最开始的初始化B 对于交替位处理 我基本没怎么做处理
B_input(packet) B的传输层处理数据包 负责给A传输ACK那些的 如果包数据正确 即向第五层应用层发送

说了一下我们需要编写的五个函数
如果对于双方都有交互的话 其实对于B的超时器还是得弄一个 但是我们现在先做单边的 交替位实验 就省了

我先说一下这个实验的网络模拟器的大致怎么回事
光看我这个文字是对整个Lab没有一个大致的了解的 我们得一步步看主函数里面的流程 先是初始化各种参数 参数包括 总共发多少条信息 丢包率 坏包率 两条信息预计发送的间隔 调试信息等级

先说一下 两条信息预计发送间隔是怎么回事 我们的信息发送是根据一个evlist来的 对于超时器 其实也是一个event 他是根据任务发生时间来排序的 这里再提一嘴 我们的消息发送过去一般是5的时间单位 两条信息时间间隔是 我们的evlist自动循环的 也就是如果设置为20 那我们的信息也就是自动平均20往外发送一条新的 而不是受我们控制 当然如果是对于重传的那些 当然是我们控制 例如 我们此刻为10的时间单位 要发送的信息5秒后到达 那就是预计15秒后到 那我们的发送任务就插入任务队列 根据时间排序 如果我们的定时器就在发送的时候启动 我们自己设置多少秒后停止定时器 启动A_timerinterrupt 比如12秒 因为来回大概是5*2=10秒 定时器就按照任务终止时间插入到任务队列进去了

上面写了很多 但原理就是这样 对于丢包 包损坏 这些都是随机数产生的 详情请见tolayer3是怎么控制 丢包和包损坏的
然后就是自己填了 刚开始调试的时候可以填写10 0 0 100 3 看看信息seq ack是否正确 然后再坏包 看看自己的重传是否成功了 把这些做了 大概就对于交替位协议版本有个认识了


交替位协议版本 代码实现


这个Lab分两篇博客来发 因为这篇博客已经快3w字了 当然是包括代码的字数 编辑字的时候开始有点点卡顿了 - - 所以分两篇来吧 这样看起来也更好看一点
这里贴了我实现的GBN的博客链接
实现可靠的传输协议(下)(GBN版本)

这里写一下我的交替位协议版本代码实现思路
首先是A发送给B包 则即刻开始计时器 发送过去文档中说了 一般都是5个时间单位 则我们代码设置的超时时间为12个时间单位
由于我们的信息发送是由evlist自动控制的 如果两个信息发送时间间隔太短的话 就不存在交替的情况了 如果忽略 不发那条信息的话 也不好 所以我们就设置长一点 按照文档推荐的1000来设置 意思就是发送完第一条消息后 1000秒后再发第二条 中间有充足的时间重传 ACK确认

我们的交替位思路如下
A->B 即刻打开超时器
B->A 如果checksum 不相等则将ack位置为0 相等的话 ack位置为1 acknum = A_packet.seq+1 表示确认
A收到消息有下面几种情况 第一个就是发送出去丢包 那就是超时器到了时间自己重发 第二个就是接受到的ack位为0 即nak 或者 checksum错了 立即关闭之前的超时器 并重新设置超时器 立即重发 第三个就是真的由于延迟 晚到了 还是会被超时器重发
A如果正确收到消息后 我们即关闭超时器 停止即可 等到evlist 下一次的自动发送

但是考虑下面这种情况 如果A->B成功发送且无错 仅因为延迟问题晚到了 后超时器又重发消息 之后连续两个ack 我们对于定时器我们每次正确收到消息的时候就自动关闭之前所有的超时器 那么第二次ack就没有超时器关闭
对于这个情况 我们的程序 发送printf("Warning: unable to cancel your timer. It wasn't running.\n"); 哈哈 其实没有超时器关就没有呗 反正都ack了 关都关完了 该关的也关了 也就不管了 对程序也没有影响

好了 就说那么多 有点困了 - - 下面直接放代码 大家凑合着看
睡醒了忽然忘了有点东西忘了说了 模板中的一些代码我也还是改了部分的 比如我的数据包里面多了个ack 有些地方根据个人需求来改 毕竟程序是自己跑的嘛 哈哈哈 去吃晚饭了!

#include <stdio.h>/* ******************************************************************ALTERNATING BIT AND GO-BACK-N NETWORK EMULATOR: VERSION 1.1  J.F.KuroseThis code should be used for PA2, unidirectional or bidirectionaldata transfer protocols (from A to B. Bidirectional transfer of datais for extra credit and is not required).  Network properties:- one way network delay averages five time units (longer if thereare other messages in the channel for GBN), but can be larger- packets can be corrupted (either the header or the data portion)or lost, according to user-defined probabilities- packets will be delivered in the order in which they were sent(although some can be lost).
**********************************************************************/#define BIDIRECTIONAL 0    /* change to 1 if you're doing extra credit *//* and write a routine called B_output */
#define  TIMER_INTERRUPT 0
#define  FROM_LAYER5     1
#define  FROM_LAYER3     2#define  OFF             0
#define  ON              1
#define   A    0
#define   B    1typedef int bool;
#define true 1
#define false 0/* a "msg" is the data unit passed from layer 5 (teachers code) to layer  */
/* 4 (students' code).  It contains the data (characters) to be delivered */
/* to layer 5 via the students transport level protocol entities.         */
struct msg
{char data[20];
};/* a packet is the data unit passed from layer 4 (students code) to layer */
/* 3 (teachers code).  Note the pre-defined packet structure, which all   */
/* students must follow. */
struct pkt
{int seqnum;int acknum;int checksum;int ack;char payload[20];
};/********* STUDENTS WRITE THE NEXT SEVEN ROUTINES *********/const float send_time_MAX = 12.0;
struct pkt A_packet;
int A_sendseq;
int B_acknum;/* called from layer 5, passed the data to be sent to other side */
A_output(message)struct msg message;
{int i,checksum = 0;for(i=0;i<20;++i){checksum += message.data[i];A_packet.payload[i] = message.data[i];}A_packet.seqnum = A_sendseq;A_packet.acknum = 0;A_packet.ack = 1;A_packet.checksum = checksum + A_packet.seqnum + A_packet.acknum + A_packet.ack;starttimer(A,send_time_MAX);tolayer3(A,A_packet);
}/* called from layer 3, when a packet arrives for layer 4 */
A_input(packet)struct pkt packet;
{int checksum = 0,i;for(i=0;i<20;++i)checksum += packet.payload[i];checksum += (packet.ack + packet.acknum + packet.seqnum);if(checksum == packet.checksum && packet.ack){A_sendseq += (packet.acknum - A_sendseq);stoptimer(A);}else if(!packet.ack || packet.acknum != A_sendseq + 1 || checksum != packet.checksum){stoptimer(A);starttimer(A,send_time_MAX);tolayer3(A,A_packet);}
}/* called when A's timer goes off */
A_timerinterrupt()
{starttimer(A,send_time_MAX);tolayer3(A,A_packet);
}/* the following routine will be called once (only) before any other */
/* entity A routines are called. You can use it to do any initialization */
A_init()
{A_sendseq = 0;
}/* the following rouytine will be called once (only) before any other */
/* entity B routines are called. You can use it to do any initialization */
B_init()
{B_acknum = -1;
}/* Note that with simplex transfer from a-to-B, there is no B_output() */
/* called from layer 3, when a packet arrives for layer 4 at B*/
B_input(packet)struct pkt packet;
{int i,checksum = 0;for(i=0;i<20;++i)checksum += packet.payload[i];checksum += (packet.seqnum + packet.acknum + packet.ack);struct pkt* p = (struct pkt*)malloc(sizeof(struct pkt));struct pkt send_packet = *p;for(i=0;i<20;++i)send_packet.payload[i] = '\0';if(checksum == packet.checksum){if(B_acknum < packet.seqnum+1) tolayer5(B,packet.payload);send_packet.seqnum = 1;send_packet.acknum = packet.seqnum + 1;send_packet.ack = 1;B_acknum = send_packet.acknum;send_packet.checksum = send_packet.seqnum + send_packet.acknum + send_packet.ack;}else{send_packet.seqnum = 1;send_packet.acknum = packet.seqnum + 1;send_packet.ack = 0;send_packet.checksum = send_packet.seqnum + send_packet.acknum + send_packet.ack;}tolayer3(B,send_packet);
}B_output(message)  /* need be completed only for extra credit */struct msg message;
{}/* called when B's timer goes off */
B_timerinterrupt()
{}/*****************************************************************
***************** NETWORK EMULATION CODE STARTS BELOW ***********
The code below emulates the layer 3 and below network environment:- emulates the tranmission and delivery (possibly with bit-level corruptionand packet loss) of packets across the layer 3/4 interface- handles the starting/stopping of a timer, and generates timerinterrupts (resulting in calling students timer handler).- generates message to be sent (passed from later 5 to 4)THERE IS NOT REASON THAT ANY STUDENT SHOULD HAVE TO READ OR UNDERSTAND
THE CODE BELOW.  YOU SHOLD NOT TOUCH, OR REFERENCE (in your code) ANY
OF THE DATA STRUCTURES BELOW.  If you're interested in how I designed
the emulator, you're welcome to look at the code - but again, you should have
to, and you defeinitely should not have to modify
******************************************************************/struct event {float evtime;           /* event time */int evtype;             /* event type code */int eventity;           /* entity where event occurs */struct pkt *pktptr;     /* ptr to packet (if any) assoc w/ this event */struct event *prev;struct event *next;};
struct event *evlist = NULL;   /* the event list */int TRACE = 1;             /* for my debugging */
int nsim = 0;              /* number of messages from 5 to 4 so far */
int nsimmax = 0;           /* number of msgs to generate, then stop */
float time = 0.000;
float lossprob;            /* probability that a packet is dropped  */
float corruptprob;         /* probability that one bit is packet is flipped */
float lambda;              /* arrival rate of messages from layer 5 */
int   ntolayer3;           /* number sent into layer 3 */
int   nlost;               /* number lost in media */
int ncorrupt;              /* number corrupted by media*/main()
{struct event *eventptr;struct msg  msg2give;struct pkt  pkt2give;int i,j;char c;init();A_init();B_init();while (1){eventptr = evlist;            /* get next event to simulate */if (eventptr==NULL)goto terminate;evlist = evlist->next;        /* remove this event from event list */if (evlist!=NULL)evlist->prev=NULL;if (TRACE>=2){printf("\nEVENT time: %f,",eventptr->evtime);printf("  type: %d",eventptr->evtype);if (eventptr->evtype==0)printf(", timerinterrupt  ");else if (eventptr->evtype==1)printf(", fromlayer5 ");elseprintf(", fromlayer3 ");printf(" entity: %d\n",eventptr->eventity);}time = eventptr->evtime;        /* update time to next event time */if (nsim==nsimmax)break;                        /* all done with simulation */if (eventptr->evtype == FROM_LAYER5){generate_next_arrival();   /* set up future arrival *//* fill in msg to give with string of same letter */j = nsim % 26;for (i=0; i<20; i++)msg2give.data[i] = 97 + j;if (TRACE>2){printf("          MAINLOOP: data given to student: ");for (i=0; i<20; i++)printf("%c", msg2give.data[i]);printf("\n");}nsim++;if (eventptr->eventity == A)A_output(msg2give);elseB_output(msg2give);}else if (eventptr->evtype ==  FROM_LAYER3){pkt2give.seqnum = eventptr->pktptr->seqnum;pkt2give.acknum = eventptr->pktptr->acknum;pkt2give.checksum = eventptr->pktptr->checksum;pkt2give.ack = eventptr->pktptr->ack;for (i=0; i<20; i++)pkt2give.payload[i] = eventptr->pktptr->payload[i];if (eventptr->eventity == A)      /* deliver packet by calling */A_input(pkt2give);            /* appropriate entity */elseB_input(pkt2give);free(eventptr->pktptr);          /* free the memory for packet */}else if (eventptr->evtype ==  TIMER_INTERRUPT){if (eventptr->eventity == A)A_timerinterrupt();elseB_timerinterrupt();}else    printf("INTERNAL PANIC: unknown event type \n");free(eventptr);}terminate:printf(" Simulator terminated at time %f\n after sending %d msgs from layer5\n",time,nsim);
}init()                         /* initialize the simulator */
{int i;float sum, avg;float jimsrand();printf("-----  Stop and Wait Network Simulator Version 1.1 -------- \n\n");printf("Enter the number of messages to simulate: ");scanf("%d",&nsimmax);       // 发送数据包数目printf("Enter packet loss probability [enter 0.0 for no loss]:");scanf("%f",&lossprob);      // 丢包率printf("Enter packet corruption probability [0.0 for no corruption]:");scanf("%f",&corruptprob);   // 包损坏率printf("Enter average time between messages from sender's layer5 [ > 0.0]:");scanf("%f",&lambda);        // 平均物理层传输时间printf("Enter TRACE:");scanf("%d",&TRACE);         // 追踪 用于调试的srand(9999);              /* init random number generator */sum = 0.0;                /* test random number generator for students */for (i=0; i<1000; i++)sum=sum+jimsrand();    /* jimsrand() should be uniform in [0,1] */avg = sum/1000.0;         // 随机概率 估计值在0.25 ~ 0.75if (avg < 0.25 || avg > 0.75){printf("It is likely that random number generation on your machine\n" );printf("is different from what this emulator expects.  Please take\n");printf("a look at the routine jimsrand() in the emulator code. Sorry. \n");exit(0);}ntolayer3 = 0;nlost = 0;ncorrupt = 0;time=0.0;                    /* initialize time to 0.0 */generate_next_arrival();     /* initialize event list */
}/****************************************************************************/
/* jimsrand(): return a float in range [0,1].  The routine below is used to */
/* isolate all random number generation in one location.  We assume that the*/
/* system-supplied rand() function return an int in therange [0,mmm]        */
/****************************************************************************/float jimsrand()
{double mmm = 0x7fff;   /* largest int  - MACHINE DEPENDENT!!!!!!!!   */float x;                   /* individual students may need to change mmm */x = rand()/mmm;            /* x should be uniform in [0,1] */return(x);
}/********************* EVENT HANDLINE ROUTINES *******/
/*  The next set of routines handle the event list   */
/*****************************************************/generate_next_arrival()
{double x,log(),ceil();struct event *evptr;char *malloc();float ttime;int tempint;if (TRACE>2)printf("          GENERATE NEXT ARRIVAL: creating new arrival\n");x = lambda*jimsrand()*2;  /* x is uniform on [0,2*lambda] *//* having mean of lambda        */evptr = (struct event *)malloc(sizeof(struct event));evptr->evtime =  time + x;evptr->evtype =  FROM_LAYER5;if (BIDIRECTIONAL && (jimsrand()>0.5) )evptr->eventity = B;elseevptr->eventity = A;insertevent(evptr);
}// 由之前生成的包中的eventtime决定 传输顺序 在队列中的什么位置
insertevent(p)struct event *p;
{struct event *q,*qold;if (TRACE>2){printf("            INSERTEVENT: time is %lf\n",time);printf("            INSERTEVENT: future time will be %lf\n",p->evtime);}q = evlist;     /* q points to header of list in which p struct inserted */if (q==NULL)    /* list is empty */{evlist=p;p->next=NULL;p->prev=NULL;}else{for (qold = q; q !=NULL && p->evtime > q->evtime; q=q->next)qold=q;if (q==NULL)    /* end of list */{qold->next = p;p->prev = qold;p->next = NULL;}else if (q==evlist) /* front of list */{p->next=evlist;p->prev=NULL;p->next->prev=p;evlist = p;}else            /* middle of list */{p->next=q;p->prev=q->prev;q->prev->next=p;q->prev=p;}}
}printevlist()
{struct event *q;int i;printf("--------------\nEvent List Follows:\n");for(q = evlist; q!=NULL; q=q->next)printf("Event time: %f, type: %d entity: %d\n",q->evtime,q->evtype,q->eventity);printf("--------------\n");
}/********************** Student-callable ROUTINES ***********************//* called by students routine to cancel a previously-started timer */
stoptimer(AorB)int AorB;  /* A or B is trying to stop timer */
{struct event *q,*qold;if (TRACE>2)printf("          STOP TIMER: stopping timer at %f\n",time);/* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next)  */for (q=evlist; q!=NULL ; q = q->next){/* remove this event */if ( (q->evtype==TIMER_INTERRUPT  && q->eventity==AorB) ){if (q->next==NULL && q->prev==NULL)evlist=NULL;         /* remove first and only event on list */else if (q->next==NULL) /* end of list - there is one in front */q->prev->next = NULL;else if (q==evlist)     /* front of list - there must be event after */{q->next->prev=NULL;evlist = q->next;}else    /* middle of list */{q->next->prev = q->prev;q->prev->next =  q->next;}free(q);return;}}printf("Warning: unable to cancel your timer. It wasn't running.\n");
}starttimer(AorB,increment)int AorB;  /* A or B is trying to stop timer */float increment;
{struct event *q;struct event *evptr;char *malloc();if (TRACE>2)printf("          START TIMER: starting timer at %f\n",time);/* be nice: check to see if timer is already started, if so, then  warn *//* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next)  */for (q=evlist; q!=NULL ; q = q->next){if (q->evtype==TIMER_INTERRUPT  && q->eventity==AorB ){printf("Warning: attempt to start a timer that is already started\n");return;}}/* create future event for when timer goes off */evptr = (struct event *)malloc(sizeof(struct event));evptr->evtime =  time + increment;evptr->evtype =  TIMER_INTERRUPT;evptr->eventity = AorB;insertevent(evptr);
}/************************** TOLAYER3 ***************/
tolayer3(AorB,packet)int AorB;  /* A or B is trying to stop timer */
struct pkt packet;
{struct pkt *mypktptr;struct event *evptr,*q;char *malloc();float lastime, x, jimsrand();int i;ntolayer3++;/* simulate losses: */if (jimsrand() < lossprob){nlost++;if (TRACE>0)printf("          TOLAYER3: packet being lost\n");return;}/* make a copy of the packet student just gave me since he/she may decide */
/* to do something with the packet after we return back to him/her */mypktptr = (struct pkt *)malloc(sizeof(struct pkt));mypktptr->seqnum = packet.seqnum;mypktptr->acknum = packet.acknum;mypktptr->ack = packet.ack;mypktptr->checksum = packet.checksum;for (i=0; i<20; i++)mypktptr->payload[i] = packet.payload[i];if (TRACE>2){printf("          TOLAYER3: seq: %d, acknum %d, check: %d ,ack %d ", mypktptr->seqnum,mypktptr->acknum,  mypktptr->checksum,mypktptr->ack);for (i=0; i<20; i++)printf("%c",mypktptr->payload[i]);printf("\n");}/* create future event for arrival of packet at the other side */evptr = (struct event *)malloc(sizeof(struct event));evptr->evtype =  FROM_LAYER3;   /* packet will pop out from layer3 */evptr->eventity = (AorB+1) % 2; /* event occurs at other entity */evptr->pktptr = mypktptr;       /* save ptr to my copy of packet *//* finally, compute the arrival time of packet at the other end.medium can not reorder, so make sure packet arrives between 1 and 10time units after the latest arrival time of packetscurrently in the medium on their way to the destination */lastime = time;/* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */for (q=evlist; q!=NULL ; q = q->next){if ( (q->evtype==FROM_LAYER3  && q->eventity==evptr->eventity) )lastime = q->evtime;}evptr->evtime =  lastime + 1 + 9*jimsrand();/* simulate corruption: */if (jimsrand() < corruptprob){ncorrupt++;if ( (x = jimsrand()) < .75)mypktptr->payload[0]='Z';   /* corrupt payload */else if (x < .875)mypktptr->seqnum = 999999;elsemypktptr->acknum = 999999;if (TRACE>0)printf("          TOLAYER3: packet being corrupted\n");}if (TRACE>2)printf("          TOLAYER3: scheduling arrival on other side\n");insertevent(evptr);
}tolayer5(AorB,datasent)int AorB;char datasent[20];
{int i;if (TRACE>2){printf("          TOLAYER5: data received: ");for (i=0; i<20; i++)printf("%c",datasent[i]);printf("\n");}
}

交替位协议版本 实现效果


其实我还是调试了很久才弄出来的- - 因为各种问题
首先得理解程序 才能写 然后自己得看各种地方出没出错 然后得注意细节 还得按照程序原本的发送方式发送 理解了才能写的出来 调试出来 下面就是大概的流程了

下面找一段非常典型的来发出来吧

理一下下面发生了什么吧
786s 发送包 预计795s到达
786s 开始计时器 预计798s重发

786s 包损坏 795s 包不仅损坏还丢失了
798s 重发定时器启动 立马开始重发 重启定时器 810s再次重发
798s 刚发的包又丢失了
810s 再次重启的定时器启动 预计811s 到达 定时器同时再次启动 预计822s重发
811s 到达 且包正常
.....

由于我的丢包率 和坏包率设置的很高好像两个都是百分之30 就出现了上面的情况 由于两条信息的间隔我设置的很高 好像是1000 就不会存在还在重发就会发出第二条新消息的情况 反正到最后就发出去了 …

这个例子挑的好像不是很好 但还是能看得出来定时器的重要性和时间设置的重要性 比特位交互的效率肯定是很低的 最常用的还是需要滑动窗口 那这篇博客就先到这里 ^^ GBN下一篇博客写

《计算机网络自顶向下》 Miscellaneous Lab1 Implementing a Reliable Transport Protocol(实现可靠的传输协议(上))相关推荐

  1. 【计算机网络】应用层 : 总结 ( 网络应用模型 C/S P2P | 域名解析 DNS | 文件传输协议 FTP | 电子邮件 | 万维网 与 HTTP ) ★★★

    文章目录 一.网络应用模型 ★ 二.域名解析过程 ★ 三.FTP 文件传输协议 四.电子邮件★ 五.万维网 和 HTTP 协议★ 一.网络应用模型 ★ 网络应用模型 : ① 客户 / 服务器 模型 ( ...

  2. 《计算机网络 自顶向下方法》 第2章 应用层 Part1

    常见的应用层协议有哪些?  HTTP(HyperText Transfer  Protocol):超文本传输协议 FTP(File Transfer Protocol):文件传输协议 SMTP(Sim ...

  3. 计算机网络自顶向下方法,第7版—第1章习题

    原博客: 计算机网络自顶向下方法,第7版--习题解答 只在原文的基础上加了一点自己的答案,其他没变,有些数学公式复制失败,建议去看原博客. 本文包含了 *Computer Networking A T ...

  4. 《计算机网络自顶向下》Wireshark实验 Lab1 Getting Started

    文章目录 专栏博客链接 前引 Lab1 Getting Started 查阅Wireshark Lab官网 获取Lab文档 利用Office Word翻译查阅Lab文档 下载Wireshark 熟悉W ...

  5. 《计算机网络自顶向下方法第7版》第三章习题解答

    传送门:<计算机网络自顶向下方法第7版>英文×习题汇总 collected by:蛋卷超人 SECTION 3.1-3.3 R1. Suppose the network layer pr ...

  6. 计算机网络自顶向下方法 第三章 运输层 3.4 可靠数据传输原理

    计算机网络自顶向下方法总结3.4可靠数据传输原理 目录 3.4 可靠数据传输原理 3.4.1 构造可带数据传输协议 3.4.2 流水线可靠数据传输协议 3.4.3 回退N步 3.4.4 选择重传 3. ...

  7. 计算机网络-自顶向下方法-笔记【第2章-应用层】

    计算机网络-自顶向下方法-笔记[第2章-应用层] 学习的课程及图片来源:中科大郑烇.杨坚全套<计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)>课 ...

  8. 计算机网络自顶向下方法知识点整理(部分)

    1-2物理媒体 1.双绞铜线 由两根绝缘的铜线组成,以规则的螺旋状排列. 无屏蔽双绞线(UTP)10Mbps~10Gbps 最终作为高速LAN联网的主导性解决方案也常用于住宅因特网接入 2.同轴电缆 ...

  9. 《计算机网络——自顶向下方法》学习笔记——应用层

    计算机网络--应用层 应用层 应用层协议原理 网络应用程序体系结构 进程通信 可供应用程序使用的运输服务 因特网提供的运输服务 应用层协议 Web和HTTP HTTP概况 非持续连接和持续连接 HTT ...

最新文章

  1. 中国电子学会青少年编程能力等级测试图形化一级编程题:无奈的Jaime
  2. R语言If、Else条件语句实战
  3. 春节后找工作被面试的经历,好岗位分享给还在找工作中的软件开发爱好者们...
  4. Python之面向对象继承和派生
  5. 【iMX6ULL】触觉 imx6ull开发板交叉编译环境搭建
  6. N551JM集显和独显切换
  7. python数据科学指南是什么_《Python数据科学指南》——导读
  8. 【剑指offer - C++/Java】13、调整数组顺序使奇数位于偶数前面
  9. RT-Thread I2C设备驱动框架的对接使用
  10. and型变量哲学家问题C语言,利用AND型信号量解决哲学家进餐问题,要windows下的C/C++的完整源代码程序。(五个哲学家五只筷子)...
  11. 当SQLServer判断不等于遇到null的时候
  12. 如何在Linux桌面环境下自动启动程序?
  13. Javascript基础--对象
  14. iOS 第三方框架-SDWebImage
  15. 毕业那天我们一起失恋
  16. ico小图标的下载及使用
  17. 【MMD动作下载】随心所欲mercy(Kimagure Mercy)
  18. 智慧社区解决方案_智慧社区建设方案——汇新云
  19. 转贴:Microsoft OLE DB Provider for SQL Server错误80040e37
  20. 整数、长整型、浮点型、字符串

热门文章

  1. UEFI+GPT+双硬盘下 搭建Windos10 和CentOS7 双系统
  2. 互联网日报 | 3月23日 星期二 | 京东集团8亿美元增持达达集团;阿里云盘正式启动公测;快手进军二手电商...
  3. Unsupervised Domain Adaptation via Structurally Regularized Deep Clustering-CVPR2020
  4. Android ContextThemeWrapper cannot be cast to android.app.Activity
  5. 华为nova8pro鸿蒙系统怎么看,华为nova8的隐藏功能_华为nova8隐藏功能怎么开启
  6. 如何将零碎信息结构化并做到有序安放,以实现知识积累?
  7. php源码安全检测,微信域名拦截安全检测API PHP源码
  8. Roson的Qt之旅#97 Qt编译报错-Could not determine which “make“ command to run
  9. 人脸核身--第二篇--启用 H5人脸认证
  10. 开发一个全功能的 Word Add-in