第6章 Socket 编程(pdf).pdf
《第6章 Socket 编程(pdf).pdf》由会员分享,可在线阅读,更多相关《第6章 Socket 编程(pdf).pdf(85页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、 1 6.3.4 Winsock 编程编程 Winsock 是一个基于是一个基于 Socket 模型的模型的 API,在,在 Windows 系统中广泛系统中广泛使用。它在使用。它在 Berkeley 接口函数的基础上,还增加了基于消息驱动机制的接口函数的基础上,还增加了基于消息驱动机制的Windows 扩展函数。扩展函数。Winsock1.1 只支持只支持 TCP/IP 网络,网络,Winsock2.2 增增加了对更多协议的支持。加了对更多协议的支持。需要包含头文件需要包含头文件 Winsock2.h,需要使用库,需要使用库 ws2_32.lib。2 TCP 客户端客户端程序工作流程程序工作
2、流程 使用使用 WSAStartup()函数检查系统协议栈安装情况;函数检查系统协议栈安装情况;使用使用 socket()函数创建客户端套接口;函数创建客户端套接口;使用使用 connect()函数发出也服务器建立连接的请求;函数发出也服务器建立连接的请求;连接建立后使用连接建立后使用 send()函数发送数据,或使用函数发送数据,或使用 recv()函数接收数据;函数接收数据;使用使用 closesocet()函数关闭套接口;函数关闭套接口;最后调用最后调用 WSACleanup()函数,结束函数,结束 Winsock Sockets API。3#include#include#pragma
3、 comment(lib,ws2_32.lib)#define SERVER_ADDRESS 192.168.0.100#define PORT 5150#define MSGSIZE 1024 int main()WSADATA wsaData;SOCKET sClient;SOCKADDR_IN server;4 struct sockaddr_in short sin_family;u_short sin_port;struct in_addr sin_addr;char sin_zero8;5 char szMessageMSGSIZE;int ret;WSAStartup(0 x02
4、02,&wsaData);sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);memset(&server,0,sizeof(SOCKADDR_IN);server.sin_family=AF_INET;server.sin_addr.S_un.S_addr=inet_addr(SERVER_ADDRESS);server.sin_port=htons(PORT);connect(sClient,(struct sockaddr*)&server,sizeof(SOCKADDR_IN);6 while(TRUE)gets(szMessage);sen
5、d(sClient,szMessage,strlen(szMessage),0);ret=recv(sClient,szMessage,MSGSIZE,0);if(SOCKET_ERROR!=ret)szMessageret=0;printf(Received%d bytes:%sn,ret,szMessage);7 else printf(Received Error!n);closesocket(sClient);WSACleanup();return 0;8 TCP 服务器端服务器端的工作流程。的工作流程。1.使用使用 WSAStartup()函数检查系统协议栈安装情况;函数检查系统协议
6、栈安装情况;2.使用使用 socket()函数创建服务器端通信套接口;函数创建服务器端通信套接口;3.使用使用 bind()函数将创建的套接口与服务器地址绑定;函数将创建的套接口与服务器地址绑定;4.使用使用 listen()函数使服务器套接口做好接收连接请求准备;函数使服务器套接口做好接收连接请求准备;5.使用使用 accept()接收来自客户端由接收来自客户端由 connect()函数发出的连接请求;函数发出的连接请求;6.根据连接请求建立连接后,使用根据连接请求建立连接后,使用 send()函数发送数据,或者使用函数发送数据,或者使用recv()函数接收数据;函数接收数据;7.使用使用
7、closesocket()函数关闭套接口(可以先用函数关闭套接口(可以先用 shutdown()函数先关函数先关闭读写通道);闭读写通道);8.最后调用最后调用 WSACleanup()函数。函数。9 6.3.5 阻塞通信与非阻塞通信阻塞通信与非阻塞通信 阻塞方式:套接字进行阻塞方式:套接字进行 I/O 操作时,函数要等待到相关的操作完成以操作时,函数要等待到相关的操作完成以后才能返回,对提高处理机的利用率不利,但编程简单。后才能返回,对提高处理机的利用率不利,但编程简单。非阻塞方式:套接字进行非阻塞方式:套接字进行 I/O 操作时,无论操作成功与否,调用都会操作时,无论操作成功与否,调用都会
8、立即返回。立即返回。阻塞方式编程简单,一个套接口的默认操作模式为阻塞,可以调用函阻塞方式编程简单,一个套接口的默认操作模式为阻塞,可以调用函数数 ioctlsocket()进行设置。进行设置。10 6.3.6 高级网络编程高级网络编程 API MFC 编程技术定义了用于网络编程的编程技术定义了用于网络编程的 Winsock 类,类名为类,类名为CAsyncSocket;还定义了一个派生于;还定义了一个派生于 CAsyncSocket 的的 CSocket 类。类。这两个类简单实用,用户可以使用它们来实现自己的网络程序(为了与别这两个类简单实用,用户可以使用它们来实现自己的网络程序(为了与别的平
9、台兼容,最好是使用伯克利的平台兼容,最好是使用伯克利 socket)。)。与前面的介绍相似,使用与前面的介绍相似,使用 MFC 的的 Winsock 类进行操作时需要使用类进行操作时需要使用Winsock2.h、Winsock32.dll 和和 ws2_32.lib 三个文件。三个文件。11 6.4 Socket IO 模型模型 一、选择(一、选择(select)模型)模型 Select(选择)模型是(选择)模型是 Winsock 中最常见的中最常见的 I/O 模型。模型。老陈非常想看到女儿的信。以至于他每隔老陈非常想看到女儿的信。以至于他每隔 10 分钟就分钟就下楼检查信箱,看是否下楼检查信
10、箱,看是否有女儿的信。在这种情况下,有女儿的信。在这种情况下,下楼检查信箱下楼检查信箱然后回到楼上耽误了老陈太多的时然后回到楼上耽误了老陈太多的时间,以至于老陈无法做其他工作。间,以至于老陈无法做其他工作。int g_iTotalConn=0;SOCKET g_CliSocketArrFD_SETSIZE;int main()sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);12 bind(sListen,(struct sockaddr*)&local,sizeof(SOCKADDR_IN);listen(sListen,3);CreateThr
11、ead(NULL,0,WorkerThread,NULL,0,&dwThreadId);while(TRUE)sClient=accept(sListen,(struct sockaddr*)&client,&iaddrSize);printf(Accepted client:%s:%dn,inet_ntoa(client.sin_addr),ntohs(client.sin_port);g_CliSocketArrg_iTotalConn+=sClient;DWORD WINAPI WorkerThread(LPVOID lpParam)13 fd_set fdread;int ret;st
12、ruct timeval tv=1,0;/秒,微妙秒,微妙 char szMessageMSGSIZE;while(TRUE)FD_ZERO(&fdread);for(i=0;i g_iTotalConn;i+)FD_SET(g_CliSocketArri,&fdread);ret=select(0,&fdread,NULL,NULL,&tv);14 if(ret=0)continue;for(i=0;i g_iTotalConn;i+)if(FD_ISSET(g_CliSocketArri,&fdread)ret=recv(g_CliSocketArri,szMessage,MSGSIZE,
13、0);if(ret=0|(ret=SOCKET_ERROR&WSAGetLastError()=WSAECONNRESET)/Client socket closed 15 else /ECHO return 0;16 服务器的几个主要动作如下:服务器的几个主要动作如下:1.创建监听套接字,绑定,监听;创建监听套接字,绑定,监听;2.创建工作者线程;创建工作者线程;3.创建一个套接字数组,用来存放当前所有活动的客户端套接字,每创建一个套接字数组,用来存放当前所有活动的客户端套接字,每 accept一个连接就更新一次数组;一个连接就更新一次数组;4.接受客户端的连接。接受客户端的连接。工作者线程
14、里面是一个死循环,一次循环完成的动作是:工作者线程里面是一个死循环,一次循环完成的动作是:1.将当前所有的客户端套接字加入到读集将当前所有的客户端套接字加入到读集 fdread 中;中;2.调用调用 select 函数;函数;3.查看某个套接字是否仍然处于读集中,如果是,则接收数据。如果接收的查看某个套接字是否仍然处于读集中,如果是,则接收数据。如果接收的数据长度为数据长度为 0,或者发生,或者发生 WSAECONNRESET 错误,则表示客户端套接字主动关错误,则表示客户端套接字主动关 17 闭,这时需要将服务器中闭,这时需要将服务器中对应的套接字所绑定的资源释放掉,然后调整套接字数对应的套
15、接字所绑定的资源释放掉,然后调整套接字数组。组。18 二、异步选择(二、异步选择(AsyncSelect)模型模型 后来,老陈使用了微软公司的新式信箱。这种信箱非常先进,一旦信箱里有后来,老陈使用了微软公司的新式信箱。这种信箱非常先进,一旦信箱里有新的信件,盖茨就会给老陈打电话:喂,大爷,你有新的信件了!从此,老陈再新的信件,盖茨就会给老陈打电话:喂,大爷,你有新的信件了!从此,老陈再也不必频繁上下楼检查信箱了。也不必频繁上下楼检查信箱了。利用这个模型,应用程序可在一个套接字上,接收以利用这个模型,应用程序可在一个套接字上,接收以 Windows 消息为基础消息为基础的网络事件通知。具体的做法
16、是在建好一个套接字后,调用的网络事件通知。具体的做法是在建好一个套接字后,调用 WSAAsyncSelect 函函数。数。19 LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)WSADATA wsd;static SOCKET sListen;SOCKET sClient;SOCKADDR_IN local,client;int ret,iAddrSize=sizeof(client);char szMessageMSGSIZE;switch(message)case WM_CREATE:2
17、0 WSAStartup(0 x0202,&wsd);sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);bind(sListen,(struct sockaddr*)&local,sizeof(local);listen(sListen,3);/Associate listening socket with FD_ACCEPT event WSAAsyncSelect(sListen,hwnd,WM_SOCKET,FD_ACCEPT);return 0;case WM_DESTROY:closesocket(sListen);WSACleanup(
18、);PostQuitMessage(0);return 0;case WM_SOCKET:21 if(WSAGETSELECTERROR(lParam)closesocket(wParam);break;switch(WSAGETSELECTEVENT(lParam)case FD_ACCEPT:sClient=accept(wParam,(struct sockaddr*)&client,&iAddrSize);/Associate client socket with FD_READ and FD_CLOSE event WSAAsyncSelect(sClient,hwnd,WM_SOC
19、KET,FD_READ|FD_CLOSE);break;22 case FD_READ:ret=recv(wParam,szMessage,MSGSIZE,0);if(ret=0|ret=SOCKET_ERROR&WSAGetLastError()=WSAECONNRESET)closesocket(wParam);else szMessageret=0;send(wParam,szMessage,strlen(szMessage),0);23 break;case FD_CLOSE:closesocket(wParam);break;return 0;return DefWindowProc
20、(hwnd,message,wParam,lParam);24 WSAAsyncSelect 是最简单的一种是最简单的一种 Winsock I/O 模型。我们需要做的仅仅模型。我们需要做的仅仅是:是:1.在在 WM_CREATE 消息处理函数中,初始化消息处理函数中,初始化 Windows Socket library,创,创建监听套接字,绑定,监听,并且调用建监听套接字,绑定,监听,并且调用 WSAAsyncSelect 函数表示我们关心在监函数表示我们关心在监听套接字上发生的听套接字上发生的 FD_ACCEPT 事件;事件;2.自定义一个消息自定义一个消息 WM_SOCKET,一旦在我们所
21、关心的套接字(监听套接,一旦在我们所关心的套接字(监听套接字和客户端套接字)上发生了某个事件,系统就会调用字和客户端套接字)上发生了某个事件,系统就会调用 WndProc 并且并且 message参数被设置为参数被设置为 WM_SOCKET;3.在在 WM_SOCKET 的消息处理函数中,分别对的消息处理函数中,分别对 FD_ACCEPT、FD_READ和和 FD_CLOSE 事件进行处理;事件进行处理;4.在窗口销毁消息在窗口销毁消息(WM_DESTROY)的处理函数中,的处理函数中,关闭监听套接字,清除关闭监听套接字,清除 25 Windows Socket library。下面下面是是用
22、于用于 WSAAsyncSelect 函数的网络事件类型函数的网络事件类型定义定义:FD_READ:应用程序想要接收有关是否可读的通知,以便读入数据应用程序想要接收有关是否可读的通知,以便读入数据 FD_WRITE:应用程序想要接收有关是否可写的通知,以便写入数据应用程序想要接收有关是否可写的通知,以便写入数据 FD_ACCEPT:应用程序想接收与进入连接有关的通知应用程序想接收与进入连接有关的通知 FD_CONNECT:应用程应用程序想接收与一次连接或者多点序想接收与一次连接或者多点 join 操作完成的通知操作完成的通知 FD_CLOSE:应用程序想接收与套接字关闭有关的通知应用程序想接收
23、与套接字关闭有关的通知 26 三、事件选择三、事件选择(EventSelect)模型模型 后来,微软的信箱非常畅销,购买微软信箱的人以百万计数后来,微软的信箱非常畅销,购买微软信箱的人以百万计数以至于盖茨以至于盖茨每天每天 24 小时给客户打电话,累得腰酸背痛,喝蚁力神都不好使小时给客户打电话,累得腰酸背痛,喝蚁力神都不好使。微软改进。微软改进了他们的信箱:在客户的家中添加一个附加装置,这个装置会监视客户的信箱,了他们的信箱:在客户的家中添加一个附加装置,这个装置会监视客户的信箱,每当新的信件来临,此装置会发出每当新的信件来临,此装置会发出新信件到达新信件到达声,提醒老陈去收信。声,提醒老陈去
24、收信。重点:重点:WSAEventSelect:把网络事件和一个事件对象连接:把网络事件和一个事件对象连接。WSAWaitForMultipleEvents:阻塞多个事件对象,只要指定事件对象中的:阻塞多个事件对象,只要指定事件对象中的一个或全部处于有信号状态,或者超时间隔到,则返回。一个或全部处于有信号状态,或者超时间隔到,则返回。27 DWORD WSAAPI WSAWaitForMultipleEvents(DWORD cEvents,const WSAEVENT FAR*lphEvents,BOOL fWaitAll,DWORD dwTimeout,BOOL fAlertable);c
25、Events:指出:指出 lphEvents 所指数组中事件对象句柄的数目。事件对象句柄的所指数组中事件对象句柄的数目。事件对象句柄的最大值为最大值为 WSA_MAXIMUM_WAIT_EVENTS。lphEvents:指向一个事件对象句柄数组的指针。:指向一个事件对象句柄数组的指针。fWaitAll:指定等待类型。若为真:指定等待类型。若为真 TRUE,则当,则当 lphEvents 数组中的所有事数组中的所有事件对象同时有信号时,函数返回。若为假件对象同时有信号时,函数返回。若为假 FALSE,则当任意一个事件对象有信,则当任意一个事件对象有信号时函数即返回。在后一种情况下,返回值指出是哪
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第6章 Socket 编程pdf 编程 pdf
限制150内