停止等待协议实验报告文档格式.docx

上传人:b****5 文档编号:17540947 上传时间:2022-12-07 格式:DOCX 页数:18 大小:329.13KB
下载 相关 举报
停止等待协议实验报告文档格式.docx_第1页
第1页 / 共18页
停止等待协议实验报告文档格式.docx_第2页
第2页 / 共18页
停止等待协议实验报告文档格式.docx_第3页
第3页 / 共18页
停止等待协议实验报告文档格式.docx_第4页
第4页 / 共18页
停止等待协议实验报告文档格式.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

停止等待协议实验报告文档格式.docx

《停止等待协议实验报告文档格式.docx》由会员分享,可在线阅读,更多相关《停止等待协议实验报告文档格式.docx(18页珍藏版)》请在冰豆网上搜索。

停止等待协议实验报告文档格式.docx

随着数据帧的到来,接收方对他们进行应答,可以每收到一帧给一个应答,也可以一次对若干帧进行应答。

如果一个帧到达时已经被破坏,接收方发送一个否定应答帧(NAK)。

在数据链路层,差错控制主要指错误检测和重传方法。

在一个帧中出现任何一个错误,接收方就返回一个否定应答帧,出错的帧就被发送方重新传送。

这个过程被称作自动重复请求(ARQ)。

数据被重传的情况有三种:

帧破坏、帧丢失和应答帧丢失。

流量控制和差错控制是结合在一起实现的,共有两种实现流量控制和差错控制的技术:

停止等待协议和滑动窗口协议。

可以用多种方法来表示一个有限状态机,对协议进行描述,以下只描述一种。

1)混合描述方法

比较实用的办法是合并一些状态,即考虑一些次要的细节。

例如,甲方的状态1和状态2,状态3和状态4都可以合并,乙的状态1和状态4,状态2和状态3也可进行合并。

这样可以用3个字符XYZ表示整个系统的状态,其中X=0或1,对应于甲方准备发[0]或[1](包括发完后等待ACK的状态);

Y=0或1,对应于乙方期望收到[0]或[1];

Z=0、l、A或-,对应于信道上传送的是[0]、[1]、ACK或出现了差错(包括丢失)。

这样,就可得出图3-24的有限状态机。

在弧线(或直线)旁边注明的数字为状态变迁的标号,其意义也注明在图3-24的右方。

假设系统一开始处在(000)状态。

这表示甲发完[0],乙期望收到[0],而信道上传送的也是[0]。

在无差错的情况下,系统的状态仅在4个状态中循环:

(000)→(01A)→(111)→(10A)→(000)→‥‥。

从理论上讲,应当共有2×

4=16种不同的状态。

去掉没有意义的组合后,还剩下10种状态,而导致状态变迁的输人事件共有9种(标号0~8)。

这种有限状态机可帮助我们检查协议是否正确。

例如,检查一下乙方会不会连续将两个0号帧送交主机。

这相当于检查一下会不会出现这种情况,即在两次出现状态变迁1之间不出现状态变迁3。

仔细检查图3-24就可发现这种情况是不会发生的。

同样方法也可用来排除连续将两个1号帧送交主机的可能。

再检查一下会不会发生甲方连续改变状态2次(如从0到1,再回到0)而乙方的状态未改变。

这种情况相当于出现了未被发现的报文丢失。

可以看出,这种情况也是不存在的。

协议必须不出现死锁。

死锁的出现是因为存在着这样的一种状态子集,其特点是:

从这一子集变迁到子集外是不可能的,而在这一子集状态的变迁总是局限于子集的几个状态。

可以看出,如图所示的自动机没有死锁现象。

3.设计方案论证

当收方收到一个正确的数据帧后,便会向发方发送一个确认帧ACK,表示发送的数据正确接收。

当发方收到确认帧后才能发送一个新的数据帧,这样就实现了接收方对发送方的流量控制。

由于通信线路质量各方面的影响,数据帧从发送方到接收方传输的过程中可能会出现差错。

为了保证数据的正确性和完整性,接收方在收到数据后,会用一定的方法对接收到的数据进行差错检验,所以接收方很容易检测出收到的数据帧是否出现差错。

当接收方发现收到的数据出现差错时,就会向发送方发送一个否认帧NAK,表示对方发送的数据错误。

发送方会根据接收方发来的信息做出相应的操作。

采用这样的有效的检错机制,数据链路层可以对上面的网络层提供了可靠的传输的服务。

三、系统运行与验证

程序分两部分:

客户程序和服务器程序。

工作过程是:

服务器首先启动,它创建套接字之后等待客户的连接;

客户启动后创建套接字,然后和服务器建立连接;

建立连接后,客户写入文件的路径,然后将文件发送到服务器,服务器要求写入保存的文件路径,收到到文件后,将接收到的文件保存到指定路径当中。

服务器端运行图:

客户端运行图

成功发送文件后的

服务器端

客户端

文件发送失败

客户端的响应

客户端向服务器端发送文件请求ENQ,但是没有收到返回帧,客户端显示sendfilefailed,而filesendfailed表明文件经过规定次数重传后文件还是发送失败。

四、总结与体会

1.分组情况

润:

负责停止等待协议模拟客户端程序的编写、调试。

毛凤阳:

负责停止等待协议模拟服务端程序的编写、调试。

黄晓明:

负责查阅相关资料,实验报告的撰写,编写头文件。

2.总结

通过本次实验及课上老师讲解,对停止等待协议有了更深刻的了解。

并且通过C/S代码的编写运行,形象地看到客户/服务器端的运作方式,对于C/S模型有了很深刻的印象以及进一步理解。

通过代码的编写,再一次熟悉Socket编程原理,掌握简单的套接字编程。

运行程序成功后,是在同一台电脑上进行C与S端的连接。

而且使用的是TCP协议,所以要模拟停止等待协议发送丢包,超时等情况比较困难。

仅仅实现了文件发送时等待应答信号超时的情况。

编程时遇到许多困难,从一个新手通过查阅相关的资料和以前的学习以及和同学之间的交流进步到逐步了解。

在设计过程中,组员之间相互促进,相互交流,共同进步。

发送端程序

//sender.cpp:

定义控制台应用程序的入口点。

//

#include"

stdafx.h"

#include<

iostream>

WinSock2.h>

string.h>

../header/ARQ.h"

../header/Exception.h"

//服务器端口

#defineSERVER_PORT2280

//最大重传次数

#defineMAXRETRY8

//传送传时时间

#defineTIMEOUT3000

#pragmacomment(lib,"

ws2_32.lib"

)//设置link时的lib库,加入ws2_32.lib到工程,此库文件与socket编程有关

//也可以在MFC过在project->

settings->

link中加入

//主要是获得Ws2_32.dll

usingnamespacestd;

SOCKETPrimaryUDP;

//定义一个socket号

charServerIP[20];

//定义数组保存服务器的IP地址

charFilePath[MAX_PATH];

//定义文件的路径存储数

//用作奇偶检校的序号

boolg_number=false;

//返回的控制字符

charg_bcc;

HANDLEm_hEvent;

voidInitWinSock()//初始化socket

{

WSADATAwsaData;

//TheWSADATAstructureisusedtostoreWindowsSocketsinitializationinformation

//returnedbyacalltotheAfxSocketInitglobalfunction.

if(WSAStartup(MAKEWORD(2,2),&

wsaData)!

=0)//TheWSAStartupfunctioninitiatesuseofWs2_32.dllbyaprocess.

//TheMAKEWORDmacrocreatesaWORDvaluebyconcatenatingthespecifiedvalues.

{

throwException("

Windowssockets2.2startupunsuccessful"

);

}

else{

printf("

Using%s(Status:

%s)\n"

wsaData.szDescription,wsaData.szSystemStatus);

withAPIversions%d.%dto%d.%d\n\n"

LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion),

LOBYTE(wsaData.wHighVersion),HIBYTE(wsaData.wHighVersion));

}

voidmksock(inttype)//创建socket号

PrimaryUDP=socket(AF_INET,type,0);

//socket()函数创建一个socket号

if(PrimaryUDP<

0)

createsocketerror"

voidBindSock()//绑定一个socket号和本地进程(用地址和端口号描述)

sockaddr_insin;

//定义一个套接字地址

sin.sin_addr.S_un.S_addr=INADDR_ANY;

//获取本地IP地址

sin.sin_family=AF_INET;

//协议族TCP/IP

sin.sin_port=0;

//系统随机获取端口号

if(bind(PrimaryUDP,(structsockaddr*)&

sin,sizeof(sin))<

0)//绑定

binderror"

boolASendto()

sockaddr_inremote;

remote.sin_addr.S_un.S_addr=inet_addr(ServerIP);

remote.sin_family=AF_INET;

remote.sin_port=htons(SERVER_PORT);

intfromlen=sizeof(remote);

//打开文件

FILE*file;

if((file=fopen(FilePath,"

rb"

))==NULL)//"

说明文件只读并按二进制方式打开

cout<

<

FilePath<

"

openerror"

endl;

returnfalse;

cout<

fileopensucceed"

//设置文件指针位置

SetFilePointer(file,0,NULL,FILE_BEGIN);

//使FILE_BEGIN指向文件开头

BSCbsc;

bsc.header=STX;

bsc.tail=ETX;

//设置为有信号状态

SetEvent(m_hEvent);

//分段序号

boolnumber=false;

unsignedlongdwRead=-1;

boolsendComplete=false;

while(!

sendComplete)

{

//清空数据

memset(bsc.data,0,MAXBSCLENGTH);

//把bsc.data前MAXBSCLENGTH字符用代替

//当前分块的奇偶序号

bsc.number=number;

//记录当前的分块序号

g_number=bsc.number;

if(dwRead==-1)//第一次应发送文件请求消息

{

//发送文件请求

bsc.bcc=ENQ;

//询问

cout<

ENQ"

;

char*filename=FilePath;

if((filename=strrchr(FilePath,'

\\'

))==NULL)//在FilePath中寻找\字符,返回指向最后一个\字符的指针

filename=FilePath;

//获取文件名

else

++filename;

strcpy(bsc.data,filename);

dwRead=0;

}

else

if(!

feof(file))//如果没有检查到file的结束符

{

bsc.bcc=SYN;

//同步

cout<

SYN"

inti=fread(bsc.data,sizeof(char),MAXBSCLENGTH,file);

//把文件读入bsc.data,返回字节数

read:

i<

\tsend:

sizeof(bsc.data)<

dwRead+=i;

//deRead等于读到的字节数

}

//发送完毕

bsc.bcc=EOT;

//结束

EOT"

sendComplete=true;

sendcomplete.sendsize:

dwRead<

fclose(file);

//MAXRETRY为最大达重传次数

for(inti=0;

MAXRETRY;

i++)

sendto(PrimaryUDP,(char*)&

bsc,sizeof(bsc),0,(sockaddr*)&

remote,fromlen);

ResetEvent(m_hEvent);

//设置为无信号状态

DWORDreslut=WaitForSingleObject(m_hEvent,TIMEOUT);

//等待信号的到来,如果在TIMEOUT时间信号不到来,

//线程不再等待,函数返回,如果想让线程一直等待,需设置该参数为INFINITE

if(reslut==WAIT_OBJECT_0)//说明事件是有信号状态返回

//收到应答消息,一种是ACK,一种是NAK

if(g_bcc==NAK)

{

if(i==MAXRETRY-1)

{

returnfalse;

}

//继续重传

continue;

}

else

{

//收到应答消息

cout<

sendsucceed"

break;

elseif(i==MAXRETRY-1)//没有收到返回帧

sendfilefailed"

returnfalse;

//开始发下一段数据

number=!

number;

returntrue;

DWORDWINAPIARecv(LPVOIDlpParam)

intsinlen=sizeof(remote);

BSCbuffer;

intiread=0;

while(true)

iread=recvfrom(PrimaryUDP,(char*)&

buffer,sizeof(buffer),0,(sockaddr*)&

remote,&

sinlen);

//处理ACK与NAK

if(iread==SOCKET_ERROR)

continue;

//与当前的分块序号进行比较,看是不是当前块的应答

if(buffer.number!

=g_number)

if(buffer.bcc==ACK||buffer.bcc==NAK)

//保存返回的控制字符

g_bcc=buffer.bcc;

SetEvent(m_hEvent);

//设置为有信号状态

return0;

int_tmain(intargc,_TCHAR*argv[])//main函数

InitWinSock();

mksock(SOCK_DGRAM);

BindSock();

Pleaseinputreceiverip:

cin>

>

ServerIP;

Pleaseinputthefilepath:

FilePath;

m_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);

//Ifthefunctionsucceeds,thereturnvalueisahandle

//totheeventobject.

//创建一个空事件对象,返回一个句柄

CreateThread(NULL,0,ARecv,NULL,0,NULL);

//TheCreateThreadfunctioncreatesathreadtoexecute

//withinthevirtualaddressspaceofthecallingprocess.

//执行ARecv函数

if(!

ASendto())

filesendfailed"

getchar();

getchar();

接收端程序:

//receiver.cpp:

)//设置link时的lib库

charFileSavePath[MAX_PATH];

voidInitWinSock()

=0)

voidmksock(inttype)

voidBindSock()

sin.sin_port=htons(SERVER_PORT);

FILE*file=NULL;

intsi

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > 财会金融考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1