计算计网络课程设计UDP文件传输程序Word格式文档下载.docx
《计算计网络课程设计UDP文件传输程序Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《计算计网络课程设计UDP文件传输程序Word格式文档下载.docx(53页珍藏版)》请在冰豆网上搜索。
2系统描述
本系统实现了文件下载和文件上传两种类型的传输功能,辅助有服务记录和断点续传的功能。
它们都是基于socket编程实现的。
系统任何传输起自一个读取或写入文件的请求,这个请求也是连接请求。
如果服务器批准此请求,则服务器打开连接,数据以定长512字节传输。
每个数据包包括一块数据,服务器发出下一个数据包以前必须得到客户对上一个数据包的确认(停等协议)。
如果一个数据包的大小小于512字节,则表示传输结束。
如果数据包在传输过程中丢失,发出方会在超时后重新传输最后一个未被确认的数据包(丢包处理)。
通信的双方都是数据的发出者与接收者,一方传输数据接收应答,另一方发出应答接收数据。
大部分的错误将会导致连接中断,错误由一个错误的数据包引起。
这个包不会被确认,也不会被重新发送,因此另一方无法接收到。
如果错误包丢失,则使用超时机制。
错误主要是由下面三种情况引起的:
不能满足请求,收到的数据包内容错误,而这种错误不能由延时或重发解释,对需要资源的访问丢失(如硬盘满)。
初始连接时候需要发出WRQ(请求写入)或RRQ(请求读取),收到一个确定应答,一个确定可以写出的包或应该读取的第一块数据。
通常确认包包括要确认的包的包号,每个数据包都与一个块号相对应,块号从1开始而且是连续的。
因此对于写入请求的确定是一个比较特殊的情况,因此它的包的包号是0。
如果收到的包是一个错误的包,则这个请求被拒绝。
在断点续传时,当发送方发出数据包后,网线被拔出之后,无论接受方接收到数据包没有,发送方都不会接收到确认帧,此时发送方会重复的发送未被确认的数据包,接收方也会等待这一个或者下一个数据包的来临,当是数据包丢失时会等待此数据帧来临,而当是确认帧丢失时,则会等待下一个数据包。
这样故障恢复后,接收方可能会接收到两个相同的数据包(确认帧丢失情况),所以接收会判断接收到的新数据包的编号是否与上一个相同,不相同则写入文件,但无论是否相同,都会发送确认帧,使发送方发送下一个数据包。
这样就能保证发送文件与接收文件大小一致。
为了防止系统长时间无响应,系统设置了超时结束机制,这与断点续传是一对矛盾。
当把超时时间设置的比路由重启的时间和网线滑落手动接上的时间略长就能很好的解决这个矛盾了。
在本系统中服务器超时设为60s客服端设为30s,这是考虑到服务器一般会比客服端更加繁忙。
3数据结构
本系统采用简单包的形式传递数据,TFTP支持一下五种类型的包:
Opcodeoperation(Opcode)
1RRQ:
Readrequest
2WRQ:
Writerequest
3DATA:
Data
4ACK:
Acknowledgment
5ERROR:
Error
各个数据包的帧结构如下:
Figure3:
RRQ/WRQ包
RRQ和WRQ包(代码分别为1和2)的格式如上所示。
文件名是NETASCII码字符,以0结束。
而MODE域包括了字符串"
netascii"
,"
octet"
或"
mail"
,名称不分大小写。
接收到NETASCII格式数据的主机必须将数据转换为本地格式。
OCTET模式用于传输文件,这种文件在源机上以8位格式存储。
如果机器收到OCTET格式文件,返回时必须与原来文件完全一样。
我们的实现建立在发送方和接收方都在相同模式(octet)的情况下。
数据在数据包中传输,其格式如上图所示。
数据包的代码为3,它还包括有一个数据块号和数据。
数据块号域从1开始编码,每个数据块依次加1,这样接收方可以确定这个包是新数据还是已经接收过的数据。
数据域从0字节到512字节。
如果数据域是512字节则它不是最后一个包,如果小于512字节则表示这个包是最后一个包。
除了ACK和用于中断的包外,其它的包均得到确认。
发出新的数据包等于确认上次的包。
WRQ和DATA包由ACK或ERROR数据包确认,而RRQ数据包由DATA或ERROR数据包确认。
WRQ数据包被ACK数据包确认,WRQ数据包的包号为0。
ACK包的操作码为4,其中的包号为要确认的数据包的包号。
ERROR包的操作码是5,它的格式如上所示。
此包可以被其它任何类型的包确认。
错误码指定错误的类型。
还可以附带错误信息。
此外本系统使用socket编程相关的结构体介绍如下:
<
1>
WSAData机构体如下
功能是:
存放windowssocket初始化信息。
.
structWSAData{
WORDwVersion;
WORDwHighVersion;
charszDescription[WSADESCRIPTION_LEN+1];
charszSystemStatus[WSASYSSTATUS_LEN+1];
unsignedshortiMaxSockets;
unsignedshortiMaxUdpDg;
charFAR*lpVendorInfo;
};
wVersion为你将使用的Winsock版本号,wHighVersion为载入的Winsock动态库支持的最高版本,注意,它们的高字节代表次版本,低字节代表主版本。
szDescription与szSystemStatus由特定版本的Winsock设置,实际上没有太大用处。
iMaxSockets表示最大数量的并发Sockets,其值依赖于可使用的硬件资源。
iMaxUdpDg表示数据报的最大长度;
然而,获取数据报的最大长度,你需要使用WSAEnumProtocols对协议进行查询。
最大数量的并发Sockets并不是什么神奇的数字,它是由可用的物理资源来决定的.。
lpVendorInfo是为Winsock实现而保留的制造商信息,这个在Windows平台上并没有什么用处.。
2>
SOCKETsocket(
intaf,
inttype,
intprotocol
);
应用程序调用socket函数来创建一个能够进行网络通信的套接字。
第一个参数指定应用程序使用的通信协议的协议族,对于TCP/IP协议族,该参数置PF_INET;
第二个参数指定要创建的套接字类型,流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM;
第三个参数指定应用程序所使用的通信协议。
该函数如果调用成功就返回新创建的套接字的描述符,如果失败就返回INVALID_SOCKET。
套接字描述符是一个整数类型的值。
每个进程的进程空间里都有一个套接字描述符表,该表中存放着套接字描述符和套接字数据结构的对应关系。
该表中有一个字段存放新创建的套接字的描述符,另一个字段存放套接字数据结构的地址,因此根据套接字描述符就可以找到其对应的套接字数据结构。
每个进程在自己的进程空间里都有一个套接字描述符表,但是套接字数据结构都是在操作系统的内核缓冲里。
3>
structsockaddr_in{
shortsin_family;
u_shortsin_port;
structin_addrsin_addr;
charsin_zero[8];
};
sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储端口号(使用网络字节顺序)
sin_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr按照网络字节顺序存储IP地址
4软件设计
4.1模块结构
客户端:
主要划分为五个部分:
1、公用数据定义。
2、输出时光标定位,使进度信息始终显示在同一行同一位置。
3、四种数据包的制作。
4、输入命令处理模块:
对键盘来的命令字符串进行解析,得到相应的命令。
5、命令相应模块:
对解析得到的命令进行响应。
主要的两个响应是下载文件及上传文件。
A.下载文件:
从连接到的服务器下载指定的文件。
B.上传文件:
向连接的服务器上传指定的文件。
4-1:
客户端详细模块图
使用到的重要函数的原型如下:
intmain(intargc,char*argv[])
函数主要完成系统初始化,启动socket,显示提示和版本信息等功能。
此处main函数输入参数没有实际意义。
intstripcmd(char*s,charcmd[][256]);
调用此函数分开输入的命令字符串得到命令代码及参数。
voidparsecmd(char*s);
解析命令,回调相应命令处理函数。
intgetcmdsubscript(char*s);
获取命令数组的下标。
voidgetfile(charcmd[][256],intpcount);
调用此函数从服务器端下载文件。
voidputfile(charcmd[][256],intpcount);
调用此函数向服务器端上传文件。
服务器端:
主要分了五个部分:
4、记录log模块:
用于记录服务器的运行情况。
5、主体功能部分:
下载模块:
对来自客户端的读请求做出响应,向客户端发送文件。
上传模块:
对来自客户端的写请求做出响应,接收来自客户端的文件。
4-2面向udp系统时序图
函数主要完成系统初始化,启动socket,监听socket和显示版本信息等功能。
voidrecord(inta,structsockaddr_in*sin,char*file)
调用此函数向log文件写入新记录。
voiddownload(structsockaddr_insour_addr,charbuffer[]);
调用此函数对读请求做出响应。
voidupload(structsockaddr_insour_addr,charbuffer[]);
调用此函数对写请求做出响应。
4.2设计流程图
4.3源程序
服务器端
1.定义代码
/*版本信息*/
#ifndefMAKEWORD
#defineMAKEWORD(l,h)((WORD)(((BYTE)(l))|(((WORD)(BYTE)(h))<
8)))
#e