通信网络设计课程设计题目:S5基于VC的Winsock的文件传输程序的设计环境要求:Windows95/98/2000/XP功能要求:能将键盘上指定的文件发送到另一台计算机上;能将接收到的数据显示到屏幕窗口内,并显示收到文件的字节数和文件传输速率;一、设计目标用TC、VisualBASIC、VisualC++、Java等编程工具和路由器、交换机、主机等网络设备提供的接口,解决网络用户之间的交互式对话问题,或计算通信网络的延迟、信道容量分配,或编码分析、通信协议分析,网络互连互通、网络规划。进一步深入掌握网络设计和通信程序的设计原理。使学生对计算机通信网络的设计实现有较深的了解,培养较高的通信网络设计能力。本课设实验将基于2013版VisualStudio进行WINSOCK的文件传输的编程实现。在WINDOWS95/98,WINDOWSNT进行WINSOCK开发使用的编程语言有很多,VC++,JAVA,DELPHI,VB等。其中VC时使用最普遍,和WINSOCK结合最紧密的。并且VC++对原来的WindowsSockets库函数进行了一系列封装,继而产生了CAsynSocket、CSocket、CSocketFile等类,它们封装着有关Socket的各种功能,是编程变得更加简单。SOCKET实际在计算机中提供了一个通信端口,可以通过这个端口与任何一个具有SOCKET接口的计算机通信。应用程序在网络上传输,接收的信息都通过这个SOCKET接口来实现。在应用开发中就像使用文件句柄一样,可以对SOCKET句柄进行读,写操作。二、设计原理套接字(Socket)是一种网络编程接口,它是对通信端点的一种抽象,提供了一种发送和接收数据的机制。套接字有两种类型:流式套接字(StreamSockets)和数据报套接字(DatagramSockets)。数据报套接字提供了一种不可靠的、非连接的数据包通信方式,它使用用户数据报协议(UDP);而流式套接字可以将数据按顺序无重复地发送到目的地,它提供的是一种可靠的面向连接的数据传输方式。使用这种套接字可以保证数据传输的正确性,它使用的是传输控制协议(TCP)。本文将使用典型的面向连接的流式套接字。在VC中进行WINSOCK的API编程开发,需要使用到下面三个文件:1WINSOCK.H:这是WINSOCKAPI的头文件。2WSOCK32.LIB:WINSOCKAPI连接库文件。3WINSOCK.DLL:WINSOCK的动态连接库,位于WINDOWS的安装目录下。通信网络设计课程设计题目:S5WINSOCK接口在WINDOWS编程环境中的位置如下图所示:==================应用程序1应用程序2网络编程API,例如WindowsSockets网络编程API,例如WindowsSockets网络通讯协议,例如TCP/IP物理通讯介质网卡驱动程序网络编程API,例如WindowsSocketsRPC或其他高层通信层==================可以看到,WINSOCK。DLL位于TCP/IP协议栈和应用程序之间。也就是说,WINSOCK管理与TCP/IP协议的接口。在网络编程中最常用的方案便是客户机/服务器模型。在这种方案中客户应用程序向服务器程序请求服务。一个服务程序通常在一个众所周知的地址监听对服务的请求,也就是说,服务进程一直处于休眠状态,直到一个客户对这个服务的地址提出了连接请求。在这个时刻,服务程序被“惊醒”并且为客户提供服务-对客户的请求作出适当的反应。虽然基于连接协议(流套接字)的服务是设计客户机/服务器应用程序时的标准,但有些服务也是可以通过无连接协议(数据报套接字)提供的。三、设计方法3.1流式套接字服务器端操作3.1.1初始化WinSock在使用WinSockAPI进行编程前,必须对它进行初始化,可用WSAStartup()函数来完成,只有此函数调用成功后,应用程序才可以再调用WindowsSock2ets中其他的API函数。该函数的原型如下:intWSAStartup(WORDwVersionRequested,LP2WSADATAlpWSAData);其中第一个参数指定了应用程序要使用的WinSock规范的最高版本;第二个参数指定了一个指向WSADATA结构的指针。通信网络设计课程设计题目:S5另外,WSACleanup()是结束WindowsSocketsDLL的使用。说明:当应用程序不再需要使用WindowsSocketsDLL时,须调用此函数来注销使用,以便释放其占用的资源。下面演示如何在程序中调用该函数。#includewinsock.h//ForWinsock2,includewinsock2.hWORDwVersion;WSADATAwsaData;wVersion=MAKEWORD(1,1);//本机Socket版本号1.1interror=WSAStartup(wVersion,&wsaData);if(error){//在初始化时出错return;}if(LOBYTE(wsaData.wVersion)!=1||HIBYTE(wsaData.wVersion)!=1){//版本不一致,通知用户,调用WSACleanup()函数退出WSACleanup();return;}3.1.2创建套接字初始化WinSock的动态连接库后,需要在服务器端建立一个监听的套接字,可以调用Socket()函数来完成,并定义此Socket所使用的通信协议。Socket()函数的原型如下:SOCKETsocket(intaf,inttype,intprotocol);参数:af:是一个地址描述,目前只提供AF-INET。type:新套接字的类型,SOCK-STREAM为创建一个流式套接字;SOCK-DGRAM为创建一个数据报套接字。protocol:指套接字所用的通讯协议。如果不想指定,可采用默认值0;此函数调用成功返回新套接字的对象,失败则返回0,可调用WSAGetLastError()函数来获取失败的原因。例:SOCKETsocket1=socket(AF-INET,SOCK-STREAM,0);//创建一个流式套接字3.1.3绑定套接字接下来要为服务器端定义的这个监听创建一个流式套接字指定的一个地址及端口(Port),这样客户端才知道所要连接的是哪一个地址的哪个端口,为此我们要调用bind()函数,该函数的原型如下:intbind(SOCKETs,conststructsockaddrFAR3name,intnamelen);参数:s:已创建好的套接字描述符;name:Socket的地址值,这个地址必须是执行这个程序所在机器的IP地址;namelen:该结构体的长度。该函数调用成功返回0,否则返回SOCKET-ERROR。如果使用者不在意地址或端口的值,那么可以设定地址为INADDR-ANY以及端口为0,WindowsSockets会自动将其设定适当的地址及端口号(1024到5000之通信网络设计课程设计题目:S5间的值)。此后可以调用getsockname()函数来获知其被设定的值。下面给出怎样创建一个端口号为6000的套接字片段。SOCKETsServSock;sockaddr-inaddr;intnSockErr;sServSock=socket(AF-INET,SOCK-STREAM,0);//创建一个流式套接字addr.sin-family=AF-INET;addr.sin-port=htons(6000);addr.sin-addr.s-addr=htonl(INADDR-ANY);//为套接字分配地址if(bind(sServSock,(LPSOCKADDR)&addr,sizeof(addr))==SOCKET-ERROR){nSockErr=WSAGetLastError();//错误处理return;}3.1.4服务器侦听连接当服务器端的套接字对象绑定完成之后,服务器端必须建立一个侦听的队列来接收客户端的连接请求。listen()函数使服务器端的套接字进入监听状态,并设定可以建立的最大连接数(目前最大值限制为5,最小值为1)。该函数的原型如下:intlisten(SOCKETs,intbacklog);参数:s:进行侦听的套接字的描述符;backlog:能接收多少连接请求。该函数调用成功返回0,否则返回SOCKET-ERROR。服务器端的Socket调用完listen()函数后,如果此时客户端调用connect()函数提出连接申请的话,Server端必须再调用accept()函数接受连接,这样服务器端和客户端才算正式完成通信程序的连接动作。3.1.5服务器接受连接请求当客户端提出连接请求时,服务器端的hwnd视窗会收到WinsockStack送来的我们自定义的一个消息,这时,我们可以分析lParam参数,然后调用相关的函数来处理此事件。为了使服务器端接受客户端的连接请求,就要使用accept()函数,该函数新建一套接字与客户端的套接字相通,原先监听的套接字继续进入监听状态,等待他人的连接要求。该函数的原型为:SOCKETaccept(SCOKETs,structsockaddrFAR3addr,intFAR3addrlen);参数:s:侦听套接字的描述符;addr:存放来连接的客户端的地址;addrlen:addr的长度。该函数调用成功返回一个新产生的套接字对象,否则返回INVALID-SOCKET,用户可调用WSAGetLastError()函数获取错误的细节信息。3.2客户端Socket的操作通信网络设计课程设计题目:S53.2.1建立客户端的套接字客户端应用程序首先也是调用WSAStartup()函数来与Winsock的动态连接库建立关系,然后同样调用socket()函数来建立一个TCP或UDP套接字(相同协定的sockets才能相通,TCP对TCP,UDP对UDP)。与服务器端的套接字不同的是,客户端的套接字可以调用bind()函数,由自己来指定IP地址及端口号;但是也可以不调用bind(),而由Winsock来自动设定IP地址及端口号。3.2.2提出连接申请客户端的套接字使用connect()函数来提出与服务器端的套接字建立连接的申请,函数的原型如下:intconnect(SOCKETs,conststructsockaddrFAR3name,intnamelen);参数:s:请求连接的套接字的描述符;name:套接字想要连接的服务器端的地址;namelen:name的长度。函数调用成功返回0,否则返回SOCKET-ERROR。3.3数据的发送与接收一般情况下流式套接字的数据发送和接收是调用send()及recv()这两个函数来完成,而数据报套接字则是用sendto()及recvfrom()这两个函数,这两个函数调用成功返回发送或接收的资料的长度,否则返回SOCKET-ERROR。发送函数如下:intsend(SOCKETs,constcharFAR3buf,intlen,intflags);参数:s:发送数据的套接字的描述符;buf:存放要传送的数据的缓冲区;len:buf的长度;flags:指定该函数被调用的方式,若flags设为MSG-DONTROUTE,则WinSock在发送数据时不会使用循环消息,若为MSGOOB,则用来发送带外数据。对于数据报套接字而言,若是数据报的大小超过限制,则将不会送出任何资料,并会传回错误值。对流式套接字而言,阻塞模式下,若是传送系统内的存储空间不够存放这些要传送的资料,send()将会被阻塞住,直到资料送完为止;如果该Socket被设定为非阻塞模式,那么将视目前的输出缓冲区空间有多少,就送出多少资料,并不会被阻塞住。flags的值可设为0或MSG-DONTROUTE及MSG-OOB的组合。接收函数如下:intrecv(SOCKETs,charFAR3buf,intlen,intf