云南大学 软件学院 计网实验5 - 图文

更新时间:2024-04-10 16:46:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

云南大学软件学院 实 验 报 告

课程: 计算机网络原理实验 任课教师:

姓名: 学号: 专业: 成绩:

实验五、传输层可靠传输协议GBN编程实验报告

一、实验目的:

1、编程实现简单可靠的数据传输GBN协议,模拟可靠数据传输

2、理解TCP协议可靠传输的差错检测、重传、累计确认、定时器的可靠传输策略。

二、实验指导:

参考教材。

三、实验要求:

编程实现一个GBN传输协议,采用编程语言不限,要求能将发送――接收流程以及处理方法表现出来.附源代码及注释并附上实验结果截图。 #include

/* ****************************************************************** ALTERNATING BIT AND GO-BACK-N NETWORK EMULATOR: VERSION 1.1 J.F.Kurose

This code should be used for PA2, unidirectional or bidirectional data transfer protocols (from A to B. Bidirectional transfer of data is for extra credit and is not required). Network properties: - one way network delay averages five time units (longer if there are 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 \/* 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 WINDOWSIZE 8 #define MAXBUFSIZE 50 定义基本常量参数 #define RTT 15.0

#define NOTUSED 0 #define NACK -1

#define TRUE 1 #define FALSE 0

#define A 0 #define B 1

int expectedseqnum; /* expected sequence number at receiver side */

int nextseqnum; /* next sequence number to use in sender side */ int base; /* the head of sender window */

struct pkt winbuf[WINDOWSIZE]; /* window packets buffer */

int winfront,winrear; /* front and rear points of window buffer */ int pktnum; /* packet number of window buffer */

struct msg buffer[MAXBUFSIZE]; /* sender message buffer */

int buffront,bufrear; /* front and rear pointers of buffer */ int msgnum; /* message number of buffer */

int packet_lost =0; int packet_corrupt=0; int packet_sent =0;

int packet_correct=0; int packet_resent =0; int packet_timeout=0;

void ComputeChecksum(packet) struct pkt *packet; { 定义一个包(按照课本要 int checksum; 求定义基本的内容,包括 int i; 校验码、序号以及确认信 号等基本信息)。 checksum = packet->seqnum; checksum = checksum + packet->acknum; for ( i=0; i<20; i++ )

checksum = checksum + (int)(packet->payload[i]); checksum = 0-checksum;

packet->checksum = checksum; }

int CheckCorrupted(packet) 对包的检查的函 struct pkt packet;

数。 {

int checksum; int i;

checksum = packet.seqnum;

checksum = checksum + packet.acknum; for ( i=0; i<20; i++ )

checksum = checksum + (int)(packet.payload[i]);

if ( (packet.checksum+checksum) == 0 ) return (FALSE); else

return (TRUE); }

/* called from layer 5, passed the data to be sent to other side */ A_output(message) struct msg message; { A端发出数据包 int i;

struct pkt sendpkt;

/* if window is not full */

if ( nextseqnum < base+WINDOWSIZE ) {

printf(\New message arrives, send window is not full, send new messge to layer3!\\n\

/* create packet */

sendpkt.seqnum = nextseqnum; sendpkt.acknum = NOTUSED; for ( i=0; i<20 ; i++ )

sendpkt.payload[i] = message.data[i];

/* computer checksum */

ComputeChecksum (&sendpkt);

/* send out packet */ tolayer3 (A, sendpkt);

/* copy the packet to window packet buffer */ winrear = (winrear+1)%WINDOWSIZE; pktnum ++;

winbuf[winrear] = sendpkt; for (i=0; i<20; i++)

winbuf[winrear].payload[i]= sendpkt.payload[i];

/* if it is the first packet in window, start timeout */ if ( base == nextseqnum ) { starttimer(A,RTT);

printf(\ }

/* update state variables */ nextseqnum = nextseqnum+1; }

/* if window is full */ else {

printf(\ /* if buffer full, give up and exit*/ if ( msgnum == MAXBUFSIZE) {

printf (\ exit (1); }

/* otherwise, buffer the message */ else {

printf(\

bufrear = (bufrear+1) % MAXBUFSIZE; for (i=0; i<20; i++)

buffer[bufrear].data[i] = message.data[i]; msgnum ++; } }

B端输出数据包。 }

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; {

数据包进入A端并进行处理,例如像对 struct pkt sendpkt; 校验码的处理以及对计时器的处理。 int i;

/* if received packet is not corrupted and ACK is received */

if ( (CheckCorrupted(packet) == FALSE) && (packet.acknum != NACK) ) { printf(\

packet_correct++;

/* delete the acked packets from window buffer */

winfront = (winfront+(packet.acknum+1-base)) % WINDOWSIZE; pktnum = pktnum - (packet.acknum+1-base); /* move window base */ base = packet.acknum+1;

stoptimer(A);

if ( base < nextseqnum) { starttimer(A,RTT);

printf (\ }

/* if buffer is not empty, send new packets */

while ( (msgnum!=0) && (nextseqnum

sendpkt.seqnum = nextseqnum; sendpkt.acknum = NOTUSED;

buffront = (buffront+1) % MAXBUFSIZE; for ( i=0; i<20 ; i++ )

sendpkt.payload[i] = buffer[buffront].data[i]; /* computer checksum */

ComputeChecksum (&sendpkt);

/* if it is the first packet in window, start timeout */ if ( base == nextseqnum ){ starttimer(A,RTT);

printf (\ }

/* send out packet */ tolayer3 (A, sendpkt);

/* copy the packet to window packet buffer */ winrear = (winrear+1)%WINDOWSIZE; winbuf[winrear] = sendpkt; pktnum ++;

/* update state variables */

nextseqnum = nextseqnum+1; /* delete message from buffer */ msgnum --; } } else

printf (\}

/* called when A's timer goes off */ A_timerinterrupt() { A端计时器的处理过程 int i;

printf(\ /* start timer */ starttimer(A,RTT);

/* resend all packets not acked */ for ( i=1; i<=pktnum; i++ ) {

packet_resent++;

tolayer3(A,winbuf[(winfront+i)%WINDOWSIZE]); }

}

/* 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端初始化。 base = 0; nextseqnum = 0; buffront = 0; bufrear = 0; msgnum = 0; winfront = 0; winrear = 0; pktnum = 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; {

B包的构建过程。 struct pkt sendpkt; int i;

/* if not corrupted and received packet is in order */

if ( (CheckCorrupted(packet) == FALSE) && (packet.seqnum == expectedseqnum)){ printf(\packet %d is correctly received, send ACK!\\n\

/* send an ACK for the received packet */ /* create packet */

sendpkt.seqnum = NOTUSED;

sendpkt.acknum = expectedseqnum; for ( i=0; i<20 ; i++ )

sendpkt.payload[i] = '0'; /* computer checksum */

ComputeChecksum (&sendpkt); /* send out packet */ tolayer3 (B, sendpkt);

/* update state variables */

expectedseqnum = expectedseqnum+1;

/* deliver received packet to layer 5 */ tolayer5(B,packet.payload); }

/* otherwise, discard the packet and send a NACK */ else {

printf(\packet %d is corrupted or not I expects, send NACK!\\n\ /* create packet */

sendpkt.seqnum = NOTUSED; sendpkt.acknum = NACK; for ( i=0; i<20 ; i++ )

sendpkt.payload[i] = '0'; /* computer checksum */

ComputeChecksum (&sendpkt); /* send out packet */ tolayer3 (B, sendpkt); } }

/* called when B's timer goes off */ B_timerinterrupt() {

B端计时器 }

以及B端的初始化

/* 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() {

expectedseqnum = 0; }

/***************************************************************** ***************** 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 corruption and packet loss) of packets across the layer 3/4 interface - handles the starting/stopping of a timer, and generates timer interrupts (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

******************************************************************/ 定义仿真部分event事件结构体: 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: */

#define TIMER_INTERRUPT 0 #define FROM_LAYER5 1 #define FROM_LAYER3 2

#define OFF 0 #define ON 1 #define A 0 #define B 1

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; 行输出到dos窗 struct msg msg2give; 口的运行部分,这 struct pkt pkt2give; 里用于调用其它 函数来实现GBN 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(\ printf(\ if (eventptr->evtype==0)

printf(\ else if (eventptr->evtype==1) printf(\ else

printf(\

printf(\ }

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(\ for (i=0; i<20; i++)

printf(\ printf(\ }

nsim++;

if (eventptr->eventity == A) A_output(msg2give); else

B_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 */ else

B_input(pkt2give);

free(eventptr->pktptr); /* free the memory for packet */ }

else if (eventptr->evtype == TIMER_INTERRUPT) {

if (eventptr->eventity == A) A_timerinterrupt(); else

B_timerinterrupt(); }

else {

printf(\ }

free(eventptr); }

terminate:

printf(\Simulator terminated at time %f\\n after sending %d msgs from layer5\\n\

printf(\ printf(\ }

init() /* initialize the simulator */ {

int i;

float sum, avg; float jimsrand();

对文件的处理函数的初始

化。 FILE *fp;

fp = fopen (\

printf(\ printf(\ fscanf(fp,\ scanf(\

printf(\ fscanf(fp, \ scanf(\

printf(\ fscanf(fp,\ scanf(\

printf(\ fscanf(fp,\ scanf(\ printf(\ fscanf(fp,\ scanf(\

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;

if (avg < 0.25 || avg > 0.75) {

printf(\ printf(\ printf(\ exit(1); }

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 = 65535; /* largest int 2147483647 65535 - 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 ****2147483647***/ /* 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(\

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; else

evptr->eventity = A; insertevent(evptr); } 向事件列表中插入一条新 的事件 insertevent(p)

struct event *p; {

struct event *q,*qold;

if (TRACE>2) {

printf(\

printf(\ }

q = evlist; /* q points to front 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(\ for(q = evlist; q!=NULL; q=q->next) { printf(\time: %f, type: %d entity: %d\\n\ }

printf(\}

停止计时器

/********************** 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(\/* 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) ) { /* remove this event */

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(\

本文来源:https://www.bwwdw.com/article/n4ur.html

Top