青岛农业大学
理学与信息科学学院
计算机网络课程设计报告
设计题目停止等待协议的编程模拟
学生专业班级计本05.3 学生姓名(学号)
指导教师王轩慧
完成时间 2007年10月17日
实习(设计)地点信息楼机房
2007年 10月 17日
停止等待协议的编程模拟
一、课程设计目的和任务
《计算机网络与通信》课程讲述计算机网络的原理,尤其是TCP/IP协议栈的原理和应用,是一门理论性、应用性、实践性都比较强的课程。《计算机网络与通信实习》是学习完《计算机网络与通信》课程后进行的一次全面的综合实习,是本专业实践性重要环节之一。
计算机网络与通信实习是从原理和实践的角度,在计算机上编程模拟实现计算机网络的基本协议。通过本实习,使我们对计算机网络的原理能有更加深刻的认识和理解,同时进一步锻炼自己的动手能力。
在这次课程设计中,我设计的的是通过编译语言,编程模拟实现数据链路层协议中的停止等协议。
二、分析与设计
1.设计任务分析:
停止等待协议是数据链路层的几个协议中最简单的协议,是具有最简单流量控制的数据链路层协议,是数据链路层各种协议的基础。此课程设计是基于winsock 编程,是在VC++6.0的MFC界面下和控制台下实现的。它采用客户机/服务器(C/S)模型,即发送数据的一端为客户端,接收数据的一端为服务器端。停止等待协议就是通过双方的收发数据而达到相互通信的目的。
本课程设计通过编程模拟实现停止等待协议,随机的发送数据,通过服务器的的接受结果和客户端的接受结果显示理解停止等待协议的原理,掌握其应用。
2.设计方案论证
当收方收到一个正确的数据帧后,便会向发方发送一个确认帧ACK,表示发送的数据正确接收。当发方收到确认帧后才能发送一个新的数据帧,这样就实现了接收方对发送方的流量控制。
由于通信线路质量各方面的影响,数据帧从发送方到接收方传输的过程中可能会出现差错。为了保证数据的正确性和完整性,接收方在收到数据后,会用一定的方法对接收到的数据进行差错检验,所以接收方很容易检测出收到的数据帧是否出现差错。当接收方发现收到的数据出现差错时,就会向发送方发送一个否认帧NAK,表示对方发送的数据错误。发送方会根据接收方发来的信息做出相应的操作。采用这样的有效的检错机制,数据链路层可以对上面的网络层提供了可靠的传输的服务。
3.详细设计
停止等待协议的算法如下:为了对停止等待算法有一个完整而准确的理解,下面给出此协议的算法。
具有最简单流量控制的数据链路层协议
假定 1:链路是理想的传输信道,所传送的任何数据既不会出差错也不会丢失。
假定 2:不管发方以多快的速率发送数据,收方总是来得及收下,并及时上交主机。
这个假定就相当于认为:接收端向主机交付数据的速率永远不会低于发送端发送数据的速率。
现在去掉上述的第二个假定。但是,仍然保留第一个假定,即主机 A 向主机 B 传输数据的信道仍然是无差错的理想信道。然而现在不能保证接收端向主机交付数据的速率永远不低于发送端发送数据的速率。
由收方控制发方的数据流,乃是计算机网络中流量控制的一个基本方法。
简单解释:收方每接受到发方一帧后,回复确认帧,让发方继续发送下一帧,并且收方将数据帧交给上层软件识别,出现错误就将帧丢掉.
在接收结点:
(1) 等待。
(2) 若收到由发送结点发过来的数据帧,
则将其放入数据链路层的接收缓存。
(3) 将接收缓存中的数据帧上交主机。
(4) 向发送结点发一信息,表示数据帧已
经上交给主机。
(5) 转到(1)
在发送结点:
(1) 从主机取一个数据帧。
(2) 将数据帧送到数据链路层的发送缓存。
(3) 将发送缓存中的数据帧发送出去。
(4) 等待。
(5) 若收到由接收结点发过来的信息(此信息的格式与内容可由双方事先商定好),则从主机取一个新的数据帧,然后转到(2)。
因此,在设计编程模拟实现停止等待协议时,因具体考虑有关帧的一些知识。帧的结构:
帧的类型帧的序号帧的确认号数据信息(可变)校验位
帧的结构
帧的类型(frame_kind)分为数据帧(data_frame),确认帧(ack_frame)和否认帧(nak_frame)三种。
发送方向接收方发送数据,是以帧为单位的,就称为数据帧。它的数据信息是可变的,但最佳的帧长为1500个字节。
接收方接收数据后,会对收到的数据帧进行差错校验,当数据正确时,就会向发送方发送一个确认帧,以表示发送方发送的数据正确接收了,反之,就会向发送方发送一个否认帧,并把这个出错的数据帧丢弃。
帧的序号(seq):
由于采用的是单工通信,帧的结构中用的控制域也很少,这个域会随着帧类型的不同而不同:
对数据帧来说:序号(seq)表示的是发送端发送的帧的序号。
对确认帧来说:序号(seq)表示的是接收方希望接收到的帧的序号,它表示seq 以前的各帧都已经正确接收,希望收到序号为seq的帧。
对否认帧来说:序号(seq)也是表示接收方希望收到的数据帧的序号,表示接收方已经收到序号为seq的帧,但是这个帧出现错误,希望发送方重新发送该数据帧。
停止等待协议采用的是单工通信,接收端向发送端发送的确认帧和否认帧中没有数据信息,它们的数据域为空。由于是单工通信,发送方只发送数据,所以发送方帧的“帧的确认号”中并没有包含任何的确认信息。
4.源代码:
发送端:(client.cpp)
#include
#include
#include
#pragma
comment(lib,"Ws2_32.lib")
#define SERVER_PORT 7300 //侦听端口
客户端向服务器传送的结构:
struct BAG
{ char packet;};
void main(int argc, char *argv[]) {
WORD wVersionRequested;
WSADATA wsaData;
int ret,i,ra,data=0;
SOCKET sClient,sListen;
struct sockaddr_in saServer;//
地址信息
struct BAG bag;
char *ptr = (char *)&bag;
BOOL fSuccess = TRUE;
WinSock初始化:
wVersionRequested = MAKEWORD(2, 2);//希望使用的WinSock DLL的版本
ret =
WSAStartup( wVersionRequested,
&wsaData );
if (ret != 0)
{
printf("WSAStartup()
failed!\n");
return;
}
确认WinSock DLL支持版本2.2:
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
{
WSACleanup();
printf("Invalid Winsock version!\n");
return;
}
创建socket,使用TCP协议:
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sClient == INVALID_SOCKET)
{
WSACleanup();
printf("socket()
failed!\n");
return;
}
构建服务器地址信息:
saServer.sin_family = AF_INET;//地址家族
saServer.sin_port =
htons(SERVER_PORT);//转化为网络字节序
连接服务器:
ret = connect(sClient, (struct sockaddr *)&saServer,
sizeof(saServer));
if (ret == SOCKET_ERROR)
{
printf("connect() successed!\n");
closesocket(sClient);//关闭套接字
WSACleanup();
return;
}
按照预定协议,客户端将发送一个数字:
for(i=97;i<=104;i++)
{ra = rand()%11;