测控网络实验指导实验二 利用停止等待协议传输数据文件一、 实验目的✧ 深入理解停止等待协议的主要特点; ✧ 深入理解停止等待协议的工作过程; ✧ 进一步掌握串行口编程的方法。
二、 实验环境该实验可以看成是前一实验的扩展和深入,它要求在串行口上利用停止等待协议实现文件的可靠传输,因此,实验需要的实验环境与实验一(异步串行通信实验)完全相同。
其所需设备、器件及电缆的制作和设备的连接方法可参阅实验一的实验手册。
三、 实验概述1. 停止等待协议图2-1 停止等待协议的基本工作过程 图2-2 数据包的丢失和确认信息的丢失示意图所谓停止等待就是在发送方发完数据报后,需要等待接收方应答信息的到发送数据包接收正确认发送数据包重发数据包发送数据包接收负确认接收正确认接收正确认接收数据包1正确 发送正确认ACK接收数据包2错误 发送负确认NAK接收数据包2正确 发送正确认ACK接收数据包3正确 发送正确认ACK接收方 发送数据包接收正确认发送数据包超时重传数据包超时重传数据包接收正确认接收数据包0正确 发送正确认ACK1接收数据包1正确 发送正确认ACK0接收数据包1正确(抛弃) 发送正确认ACK0接收方发送数据包超时超时来。
如果发送方接收到正确认信息ACK,那么说明接收方已经正确接收到上一数据包,发送方就可以发送下一数据包;如果发送方接收到负责确认信息NAK,说明接收方收到的数据包是错误的,发送方应该重发,如图2-1所示。
为了保证数据传输的可靠性,实际的停等协议并不像上述的那么简单。
在实际应用环境中,至少应该考虑以下两种情况。
(1)数据包丢失数据包在传输过程中丢失,接收方未收到任何数据,如图2-2所示。
由于接收方不知道数据已经发送,因此它不可能给出正确认(ACK)信息或负确认信息(NAK)信息。
为了解决这个问题,发送方需要在发送一个数据包后启动一个定时器。
一旦在规定时间内没有收到接收方的任何信息,则认为数据包丢失,需要重发该数据包。
如果重传一个数据包的次数达到一定值,则认为数据通信信道存在严重问题,数据传输失败。
(2)确认信息丢失或出错接收方正确接收到数据包,但确认信息在传输过程中丢失或出错,如图2-2所示。
这时发送方也不能确定接收方是否收到了数据包。
这个问题的解决也是采用定时器的方法,在定时器溢出后重发数据包。
但是为了保证接收到的数据不重复,需要给数据包编号。
当接收方再次收到同样编号的数据包时,将该包丢弃,并认为上次发送的确认信息丢失或出错,需要重传该确认信息。
对于停等协议,至少需要两个编号(通常为0和1)。
第一个包的编号为0,第二个包的编号为1,第三个包的编号再为0……如果接收方连续收到了相同编号的数据包,则发生了重复,需要将其丢弃。
同时确认信息也需要进行编号,通常用ACK1表示收到编号为0的数据包,并准备接收编号为1的数据包。
同样的,ACK0则表示下一个准备接收到的数据包的编号为0。
2.停止等待协议实例——BSCBSC是一种典型的面向字符型停止等待协议,它使用了ASCII码中的10个控制字符完成通信控制功能,并规定了数据报文、控制报文的格式以及协议的操作过程。
由于规程简单、容易实现,比较适宜在中低速网络(如电话网)中使用。
控制字符:BSC协议中使用的控制字符的符号、名称、ASCII编码及功能说明如表2-1所示。
表2-1 BSC协议中使用的控制字符与功能⏹报文格式BSC协议规定了数据报文格式和控制报文格式。
数据报文格式如图2-3所示,其中SYN为同步字符,接收方在收到2个以上的SYN后就可以进入数据报的接收状态。
报头字段由SOH开始,它是一个可选项,可由用户自己定义,用于存放地址、路径、发送日期等信息。
正文字段由STX开始,其正文字段的长度未作具体规定。
如果正文太长,要将其分成几块传输,每块用ETB结束正文字段。
当全部正文传输结束后,需要用ETX结束正文字段。
BCC为校验字段。
在BSC中,既可以使用奇偶校验,也可以使用CRC 校验。
图2-3 BSC数据报文格式控制报文格式比较简单,基本上是使用一些控制字符序列的组合。
经常使用的控制报文如表2-2所示。
表2-2 BSC常用控制报文及控制字符序列⏹透明数据传输在面向字符协议数据报文中,数据是以字符为单位组成的。
在正文数据中完全可能出现与控制字符代码相同的数据字符,这就会造成误解。
例如,正文中也可能出现与文终字符ETX的代码相同的数据字符。
如果不进行特殊的处理,接收方会误认为是正文结束。
为了解决这个问题,BSC定义了转义字符DLE。
当正文出现与控制字符编码相同的数据字符时,要在数据字符前增加一个DLE。
这样,接收方在收到一个DLE后就可以预知下一个字符是数据字符,而不会把它当作控制字符进行处理。
DLE本身也是控制字符,当它出现在正文中时,也需要增加DLE。
BSC协议的执行过程BSC协议执行过程大致可以分为数据链路建立阶段、数据传输阶段和数据链路拆除阶段。
在正式发送数据之前,发送方通过发送ENQ询问接收方是否同意建立链路,进而进行数据传输。
接收方如果同意则向发送方返回ACK信息;否则返回NAK信息。
在数据链路建立之后,发送方就可以向接收方发送数据报文。
接收方根据接收到数据报文携带的BCC字段来判定数据报文是否接收正确。
如果正确则返回ACK信息;否则返回NAK信息,要求发送方重传。
数据传输完成之后,发送发通过发送EOT拆除链路。
3.简化的停止等待协议实验在不影响停止等待协议基本思想的前提下进行简化,以简化编程过程。
简化的停止等待协议只使用STX、ETX、EOT、ENQ、ACK和DLE6个控制字符,数据报文的格式如图2-4所示。
STX 编号0/1 正文BCC ETX图2-4 简化的停止等待协议数据报文格式每个报文以STX开始,以ETX结束。
报文编号0或1位于STX之后。
正文为可变长度区域,通常为256、512、1024、2048字节等。
BCC是对正文字段的奇偶校验码。
需要发送信息的一方以ENQ请求建立链路。
当收到接收方的ACK0后,发送发就可以开始发送数据报文。
接收方在收到一个数据报后,对其编号和BCC 进行检查,如果正确则返回ACK0(或ACK1)。
如果错误则抛弃该数据报,等待发送方超时后重新发送该报文。
在所有的数据发送完成后,发送方发送EOT 信息,结束本次通信。
四、实验内容与步骤本实验将实现一个基于串行口的文件传输程序。
它可以通过串行口将用户指定的文件从一台计算机发送至另一台计算机,其界面示意图如图2-5所示。
由于本实验要在串口上实现停等协议,因此实验一介绍的有关串口上的数据收发函数和过程也适用于本实验。
此外,在本次实验中需要注意以下问题:1.日志列表该编程实验的主要目的是深入理解停止等待协议的主要特点和工作过程。
因此在程序界面的设计中一定要留有日志位置,以记录发送和接收的整个过程,如图2-5所示。
图2-5 利用停止等待协议实现文件传输程序界面示意图2.日志列表该编程实验的主要目的是深入理解停止等待协议的主要特点和工作过程。
因此在程序界面的设计中一定要留有日志位置,以记录发送和接收的整个过程,如图2-5所示。
3.发送和接收文件的选择选择需要发送的文件或指定需要存储的文件可以使用CFileDialog类。
CFileDialog类的使用方法如下:构造CFileDialog类对象。
CFileDialog类的构造函数如下:explicit CFileDialog(BOOL bOpenFileDialogLPCTSTR lpszDefExt=NULLLPCTSTR lpszFileName=NULLDWORD dwFlags=OFN_HIDEREADONL Y| OFN_OVERWRITEPROMPTLPCTSTR lpszFilter=NULLCWnd* pParentWnd=NULLDWORD dwSize=0);其中各参数主要含义如下:bOpenFileDialog如果设置为TRUE,那么将构造“打开”对话框;如果设置为FALSE,那么将构造“保存为”对话框;LpszDefExt指定默认的扩展名,如果用户在文件名编辑对话框中没有指定扩展名,那么lpszDefExt将自动添加到文件名之后。
如果不希望系统自动添加扩展名,则将该参数置为NULL;lpszFileName为对话框中初始显示的文件名;dwFlags由一个或者多个标志组成,用于对话框的定制,例如标志OFN_HIDEREADONLY告诉系统在显示文件列表时隐藏只读文件;lpszFilter文件名过滤器,用于指定显示在文件列表中的文件类型;pParentWnd指向对话框父窗口的指针;dwSize将由MFC选择合适的值,用户将其值设置为默认值0即可。
✧调用CFileDialog类的成员函数DoModal显示对话框。
✧如果DoModal函数返回值为IDOK,那么可以通过成员函数GetPathName 得到选择或指定文件的完整路径名和文件名。
4.磁盘文件操作可以采用多种不同的方法对磁盘文件进行读写操作,其中最常用的是利用CFile类。
CFile类拥有Open、Read、Write、Close等成员函数,通过这些成员函数可以对磁盘文件进行读写操作。
CFile类的一种主要的使用使用方法如下:✧构造CFile类对象。
✧调用CFile类成员函数Open打开某一特定的文件并指定打开的方式和类型。
成员函数Open的原型如下:virtual BOOL Open(LPCTSTR lpszFileNameUNIT nOpenFlagsCfileException* pError=NULL);其中lpszFileName为指定需要打开文件的文件名和其路径;nOpenFlags定义打开文件的共享模式和存取模式。
这些模式可以通过一系列的标志进行定义,如modeRead为只读模式、modeWrite为只写模式、modeReadWrite为读写模式、typeText指定文件以文本方式打开、typeBinary指定文件以二进制方式打开。
这些标志可以通过|进行组合,用于指定两种以上的模式。
✧在成功打开文件后,利用Read和Write成员函数对文件进行读写操作。
Read和Write的原型如下:virtual UNIT Read(viod * lpBufUNIT nCount);virtual viod Write(const void * lpBufUNIT nCount);在Read和Write函数中,各参数的意义如下:lpBuf指向用于存储读出数据(写入数据)的缓冲区;nCount指明在本次操作中可以读取(写入)的最多字节数。
在对打开的文件进行操作时,Read函数将返回本次操作实际读取的字节数,而Write函数在发生错误(如磁盘满等)时将显示一个例外。