基于VC的Winsock的文件传输程序的设计_第1页
基于VC的Winsock的文件传输程序的设计_第2页
基于VC的Winsock的文件传输程序的设计_第3页
基于VC的Winsock的文件传输程序的设计_第4页
基于VC的Winsock的文件传输程序的设计_第5页
已阅读5页,还剩20页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、通信网络设计课程设计 题目:S5基于VC 的Winsock 的文件传输程序的设计 环境要求:Windows95/98/2000/XP功能要求:能将键盘上指定的文件发送到另一台计算机上;能将接收到的数据显示到屏幕窗口内,并显示收到文件的字节数和文件传输速率;一、 设计目标用TC、Visual BASIC、Visual C+、Java 等编程工具和路由器、交换机、主机等网络设备提供的接口,解决网络用户之间的交互式对话问题,或计算通信网络的延迟、信道容量分配,或编码分析、通信协议分析,网络互连互通、网络规划。进一步深入掌握网络设计和通信程序的设计原理。使学生对计算机通信网络的设计实现有较深的了解,培

2、养较高的通信网络设计能力。本课设实验将基于2013版Visual Studio进行WINSOCK的文件传输的编程实现。在WINDOWS95/98,WINDOWSNT进行WINSOCK开发使用的编程语言有很多,VC+,JAVA,DELPHI,VB等。其中VC时使用最普遍,和WINSOCK结合最紧密的。并且VC+对原来的WindowsSockets库函数进行了一系列封装,继而产生了CAsynSocket、CSocket、CSocketFile等类,它们封装着有关Socket的各种功能,是编程变得更加简单。SOCKET实际在计算机中提供了一个通信端口,可以通过这个端口与任何一个具有SOCKET接口的

3、计算机通信。应用程序在网络上传输,接收的信息都通过这个SOCKET接口来实现。在应用开发中就像使用文件句柄一样,可以对SOCKET句柄进行读,写操作。二、 设计原理套接字(Socket) 是一种网络编程接口,它是对通信端点的一种抽象,提供了一种发送和接收数据的机制。套接字有两种类型:流式套接字(St ream Socket s) 和数据报套接字(Datagram Socket s) 。数据报套接字提供了一种不可靠的、非连接的数据包通信方式,它使用用户数据报协议(UDP) ;而流式套接字可以将数据按顺序无重复地发送到目的地,它提供的是一种可靠的面向连接的数据传输方式。使用这种套接字可以保证数据传

4、输的正确性,它使用的是传输控制协议( TCP) 。本文将使用典型的面向连接的流式套接字。 在VC中进行WINSOCK的API编程开发,需要使用到下面三个文件: 1 WINSOCK.H: 这是WINSOCK API的头文件。2 WSOCK32.LIB: WINSOCK API连接库文件。 3 WINSOCK.DLL: WINSOCK的动态连接库,位于WINDOWS的安装目录下。WINSOCK接口在WINDOWS编程环境中的位置如下图所示:= = 可以看到,WINSOCK。DLL位于TCP/IP协议栈和应用程序之间。也就是说,WINSOCK管理与TCP/IP协议的接口。在网络编程中最常用的方案便是

5、客户机/服务器模型。在这种方案中客户应用程序向服务器程序请求服务。一个服务程序通常在一个众所周知的地址监听对服务的请求,也就是说,服务进程一直处于休眠状态,直到一个客户对这个服务的地址提出了连接请求。在这个时刻,服务程序被“惊醒”并且为客户提供服务对客户的请求作出适当的反应。虽然基于连接协议(流套接字)的服务是设计客户机/服务器应用程序时的标准,但有些服务也是可以通过无连接协议(数据报套接字)提供的。三、 设计方法3.1 流式套接字服务器端操作3.1.1初始化WinSock在使用WinSock API 进行编程前,必须对它进行初始化,可用WSAStartup () 函数来完成,只有此函数调用成

6、功后,应用程序才可以再调用Windows Sock2et s 中其他的API 函数。该函数的原型如下:int WSAStartup (WORD wVersionRequested ,L P2WSADATA lpWSAData) ;其中第一个参数指定了应用程序要使用的WinSock 规范的最高版本;第二个参数指定了一个指向WSADATA 结构的指针。另外,WSACleanup()是结束 Windows Sockets DLL 的使用。说明: 当应用程序不再需要使用 Windows Sockets DLL时,须调用此函数来注销使用,以便释放其占用的资源。下面演示如何在程序中调用该函数。# incl

7、ude / / For Winsock2 ,include winsock2. hWORD wVersion ;WSADATA wsaData ;wVersion = MAKEWORD(1 ,1) ; / / 本机Socket版本号1. 1int error = WSAStartup (wVersion , &wsaData) ;if (error) / / 在初始化时出错return ;if (LOBYTE(wsaData. wVersion) ! = 1| | HIBYTE(wsaData. wVersion) ! = 1) / / 版本不一致,通知用户,调用WSACleanup () 函

8、数退出WSACleanup () ;return ;3.1.2 创建套接字初始化WinSock 的动态连接库后,需要在服务器端建立一个监听的套接字,可以调用Socket ( ) 函数来完成,并定义此Socket 所使用的通信协议。Socket () 函数的原型如下:SOCKET socket ( int af , int type , int protocol ) ;参数: af :是一个地址描述,目前只提供AF- INET。type :新套接字的类型,SOCK- STREAM 为创建一个流式套接字;SOCK-DGRAM 为创建一个数据报套接字。protocol :指套接字所用的通讯协议。如果

9、不想指定,可采用默认值0 ;此函数调用成功返回新套接字的对象,失败则返回0 ,可调用WSAGetLast Error () 函数来获取失败的原因。例:SOCKET socket1 = socket (AF- INET ,SOCK- STREAM ,0) ; / / 创建一个流式套接字3.1.3 绑定套接字接下来要为服务器端定义的这个监听创建一个流式套接字指定的一个地址及端口(Port),这样客户端才知道所要连接的是哪一个地址的哪个端口,为此我们要调用bind () 函数,该函数的原型如下:int bind ( SOCKET s , const st ruct sockaddr FAR 3 na

10、me ,int namelen ) ;参数: s :已创建好的套接字描述符;name :Socket 的地址值,这个地址必须是执行这个程序所在机器的IP地址;namelen :该结构体的长度。该函数调用成功返回0 ,否则返回SOCKET- ERROR。如果使用者不在意地址或端口的值,那么可以设定地址为INADDR-AN Y以及端口为0 ,Windows Socket s 会自动将其设定适当的地址及端口号(1024 到5000 之间的值) 。此后可以调用get sockname () 函数来获知其被设定的值。下面给出怎样创建一个端口号为6000 的套接字片段。SOCKET sServSock ;

11、sockaddr-in addr ;int nSockErr ;sServSock = socket (AF- INET ,SOCK- STREAM ,0) ; / / 创建一个流式套接字addr. sin-family = AF- INET ;addr. sin-port = htons (6000) ;addr. sin-addr. s-addr = htonl ( INADDR-AN Y) ; / / 为套接字分配地址if (bind (sServSock , (L PSOCKADDR) &addr ,sizeof (addr) ) = = SOCKET- ERROR) nSockErr

12、 = WSAGetLast Error () ; / / 错误处理return ;3.1.4 服务器侦听连接当服务器端的套接字对象绑定完成之后,服务器端必须建立一个侦听的队列来接收客户端的连接请求。listen () 函数使服务器端的套接字进入监听状态,并设定可以建立的最大连接数(目前最大值限制为5 , 最小值为1) 。该函数的原型如下:int listen ( SOCKET s , int backlog ) ;参数: s :进行侦听的套接字的描述符;backlog :能接收多少连接请求。该函数调用成功返回0 ,否则返回SOCKET- ERROR。服务器端的Socket 调用完listen

13、( ) 函数后,如果此时客户端调用connect () 函数提出连接申请的话,Server 端必须再调用accept ( ) 函数接受连接,这样服务器端和客户端才算正式完成通信程序的连接动作。3.1.5 服务器接受连接请求当客户端提出连接请求时,服务器端的hwnd 视窗会收到Winsock Stack 送来的我们自定义的一个消息,这时,我们可以分析lParam 参数,然后调用相关的函数来处理此事件。为了使服务器端接受客户端的连接请求,就要使用accept () 函数,该函数新建一套接字与客户端的套接字相通,原先监听的套接字继续进入监听状态,等待他人的连接要求。该函数的原型为:SOCKET ac

14、cept ( SCOKET s , st ruct sockaddr FAR 3 addr ,int FAR 3 addrlen ) ;参数:s :侦听套接字的描述符;addr :存放来连接的客户端的地址;addrlen :addr 的长度。该函数调用成功返回一个新产生的套接字对象,否则返回INVAL ID- SOCKET ,用户可调用WSAGetLast Error () 函数获取错误的细节信息。3.2 客户端Socket 的操作3.2.1 建立客户端的套接字客户端应用程序首先也是调用WSAStartup () 函数来与Winsock 的动态连接库建立关系,然后同样调用socket () 函

15、数来建立一个TCP 或UDP 套接字(相同协定的socket s 才能相通,TCP 对TCP ,UDP 对UDP) 。与服务器端的套接字不同的是,客户端的套接字可以调用bind () 函数,由自己来指定IP 地址及端口号;但是也可以不调用bind () ,而由Winsock 来自动设定IP 地址及端口号。3.2.2 提出连接申请客户端的套接字使用connect () 函数来提出与服务器端的套接字建立连接的申请,函数的原型如下:int connect ( SOCKET s , const st ruct sockaddr FAR 3 name , int namelen ) ;参数:s :请求连

16、接的套接字的描述符; name :套接字想要连接的服务器端的地址; namelen : name 的长度。函数调用成功返回0 ,否则返回SOCKET- ERROR。3.3 数据的发送与接收一般情况下流式套接字的数据发送和接收是调用send () 及recv() 这两个函数来完成,而数据报套接字则是用sendto ( ) 及recvf rom ( ) 这两个函数,这两个函数调用成功返回发送或接收的资料的长度,否则返回SOCKET- ERROR。发送函数如下:int send ( SOCKET s , const char FAR 3 buf ,int len , int flags ) ;参数:

17、s :发送数据的套接字的描述符;buf :存放要传送的数据的缓冲区;len : buf 的长度;flags :指定该函数被调用的方式,若flags 设为MSG-DONTROU TE ,则WinSock 在发送数据时不会使用循环消息,若为MSGOOB,则用来发送带外数据。对于数据报套接字而言,若是数据报的大小超过限制,则将不会送出任何资料,并会传回错误值。对流式套接字而言,阻塞模式下,若是传送系统内的存储空间不够存放这些要传送的资料,send () 将会被阻塞住,直到资料送完为止;如果该Socket 被设定为非阻塞模式,那么将视目前的输出缓冲区空间有多少,就送出多少资料,并不会被阻塞住。flag

18、s 的值可设为0 或MSG-DONTROU TE 及MSG-OOB 的组合。接收函数如下:int recv( SOCKET s , char FAR 3 buf , int len , int flags ) ;参数:s :发送数据的套接字的描述符;buf :存放接收到的数据的缓冲区;len : buf 的长度;flags :指定该函数被调用的方式。对流式套接字而言,我们可以接收到目前输入缓冲区内有效的资料,但其数量不超过len 的大小。至此面向连接的流式套接字中服务器端和客户端的通信过程已经完成。四、 程序框图其编程模型分别如下:一般在使用中,面向连接协议的SOCKET编程模型应用最为广泛,

19、因为面向连接协议提供了一系列的数据纠错功能,可以保证在网络上传输的数据及时、无误地到达对方。 总的来说,使用SOCKET接口(面向连接或无连接)进行网络通信时,必须按下面简单的四步进行处理:1、程序必须建立一个 SOCKET。2、程序必须按要求配置此SOCKET。也就是说,程序要么将此SOCKET连接到远方的主机上,要么给此SOCKET指定一个本地协议端口。3、程序必须按要求通过此SOCKET发送和接收数据。4、程序必须关闭此SOCKET。五、 程序功能首先,在本机上运行服务端程序,然后就可以在同一网络的本机另一个窗口继续运行客户端程序,登录到服务器上,运行窗口就可以进行文件传输。 1、服务端

20、 核心代码在 CServerViwe 类中,有一个 SOCKET 变量 m_hServerSocket 和 SOCKET 数组 m_aClientSocketMAXClient(MAXClient:所定义的接收连接客户的最大数目),m_hServerSocket 用来在指定的端口(1000)进行侦听,如果有客户端请求连接,则在 m_aClientSocket 数组中查找一个空 socket,将客户端的地址赋予此 socket。每当一个 ClientSocket 接收到信息,都将会向窗口发一条消息。程序接收到这个消息后,再把接收到的信息发送给每一个 ClientSocket。2、客户端 客户端比

21、较简单,核心代码在 CClientDlg 类中。只有一个 socket 变量 m_hSocket,与服务端进行连接。连接建立好后,通过此 SOCKET 发送和接收信息。为了简化设计,用户名在客户端控制,服务器端只进行简单的接收信息和“广播”此信息,不进行名字校验,也就是说,可以有同名客户登录到服务端。这个程序设计虽然简单,但是已经具备了聊天室的最基本的功能。程序在VC+ 6.0 下编译通过,在使用 TCP/IP 协议的 WINDOWS 95/98 对等局域网 和使用 TCP/IP 协议的 WINDOWS NT 局域网上运行良好。六、 程序清单客户端代码#include /客户端#include

22、 #pragma comment(lib,ws2_32.lib)#define SIZE 1024*8int main()FILE *fp;int err;int length=0;SOCKET clientSocket;SOCKADDR_IN clientsock_in;char receiveBuf100=0;char ip_addr16=127.0.0.1; /IPWORD versionRequired;WSADATA wsaData;versionRequired=MAKEWORD(1,1); /Socket生存版本号1.1err=WSAStartup(versionRequired

23、,&wsaData);/Socket初始化if (!err) printf(客户端嵌套字已经打开!n);/return 0;else printf(客户端的嵌套字打开失败!n); return 0;/结束clientSocket=socket(AF_INET,SOCK_STREAM,0); /创建了可识别套接字,流式套接字,tcp/ip协议printf(请输入主机IP:n);scanf(%s,ip_addr);/连接服务器clientsock_in.sin_addr.S_un.S_addr=inet_addr(ip_addr);/ip地址等于clientsock_in.sin_family=A

24、F_INET; /地址描述clientsock_in.sin_port=htons(6000);connect(clientSocket,(SOCKADDR*)&clientsock_in,sizeof(SOCKADDR);/开始连接recv(clientSocket,receiveBuf,101,0); /接受成功返回信息,存放到接受bufferprintf(%sn,receiveBuf);char path100=0;gets(path);int i=0;do printf(请输入文件地址:n); gets(path); while(pathi!=0) if(pathi=/) pathi=

25、; i+; i=0; if(fp=fopen(path,rb)=NULL) i=1; printf(文件未打开n); while(i);fseek(fp,0L,SEEK_END); length=ftell(fp);printf(待传送文件大小: %dn,length);printf(文件已经打开 等待主机消息.n);/得到主机开始传送消息recv(clientSocket,receiveBuf,101,0);printf(%sn,receiveBuf);if(strcmp(receiveBuf,开始传送)=0) /传送文件长度 char sendBuf20; ltoa(length,send

26、Buf,10); send(clientSocket,sendBuf,21,0); fseek(fp,0L,SEEK_SET); /传送文件 long int y=0; double cent; char transSIZE; while(!feof(fp) fread(trans,1,SIZE,fp); y=y+SIZE; if(ylength) cent=(double)y*100.0/(double)length; printf(已发送: %4.2fn,cent); send(clientSocket,trans,SIZE+1,0); else send(clientSocket,tra

27、ns,length+SIZE-y+1,0); closesocket(clientSocket); WSACleanup(); fclose(fp);printf(文件发送完毕n);system(pause);服务器代码#include /服务端#include #pragma comment(lib,ws2_32.lib) /API链接库文件#define SIZE 1024*8 /缓冲区大小void main()/创建套接字WORD myVersionRequest;WSADATA wsaData;myVersionRequest=MAKEWORD(1,1); /Socket生存版本号1.

28、1int err;err=WSAStartup(myVersionRequest,&wsaData); /Socket初始化if (!err) printf(已打开套接字n); else /进一步绑定套接字 printf(嵌套字未打开!); return;SOCKET serSocket=socket(AF_INET,SOCK_STREAM,0);/创建了可识别套接字,流式套接字,tcp/ip协议SOCKADDR_IN addr;addr.sin_family=AF_INET;addr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);/ip地址addr.sin_p

29、ort=htons(6000);/绑定端口bind(serSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR);/Ip与Socket连接listen(serSocket,5);/套接字描述符,最多的连接数1-5,监听/开始进行监听/SOCKADDR_IN clientsocket;int len=sizeof(SOCKADDR);SOCKET serConn;char sendBuf50; /缓冲区预大小serConn=accept(serSocket,(SOCKADDR*)&clientsocket,&len);/如果这里不是accept而是conection的话

30、。就会不断的监听sprintf(sendBuf,Successfully,welcome %s to Leon,inet_ntoa(clientsocket.sin_addr);/找对对应的IP并且将这行字打印到那里send(serConn,sendBuf,strlen(sendBuf)+1,0);FILE *fp;lable1: printf(客户端已打开n请输入存放文件地址:n);char path100=0;int i=0;while(pathi!=0) if(pathi=/) pathi=; i+;gets(path);if(fp=fopen(path,wb)=NULL) printf

31、(文件未打开n); goto lable1;else long t1=GetTickCount();/程序段开始前取得系统运行时间(ms) Sleep(500); /休眠时间 printf(文件已打开 开始文件传输.n); /发送开始标志 send(serConn,开始传送,strlen(开始传送)+1,0); /得到文件大小 char datalength20; long int length=0; recv(serConn,datalength,21,0); length=atol(datalength); printf(得到文件大小: %dn,length); /开始传送 double

32、cent=0.0; char receiveBufSIZE; long int x=0; while (1) x=x+SIZE; if(xlength) cent=(double)x*100.0/(double)length; /计算每段buffer占的百分比=8*1024/总文件大小 printf(已接收: %4.2fn,cent); recv(serConn,receiveBuf,SIZE+1,0); fwrite(receiveBuf,1,SIZE,fp); else recv(serConn,receiveBuf,length+SIZE-x+1,0); printf(文件接收完毕n); fwrite(receiveBuf,1,length+SIZE-x,fp); long t2=GetTickCount();/程序段结束后取得系统运行时间(ms) long v; v=length/(t2-t1); printf(运行时间:%ldn,t2-t1); printf(传输速率:%ldn,v); fclose(fp); break; closesocket(serConn);/关闭WSACleanup();/

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论