网络编程技术(西电课件)_第8章-1.ppt_第1页
网络编程技术(西电课件)_第8章-1.ppt_第2页
网络编程技术(西电课件)_第8章-1.ppt_第3页
网络编程技术(西电课件)_第8章-1.ppt_第4页
网络编程技术(西电课件)_第8章-1.ppt_第5页
已阅读5页,还剩58页未读, 继续免费阅读

下载本文档

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

文档简介

1、网络编程技术,第8章 WinSock的I/O模型 (1),本次课内容: 回顾阻塞和非阻塞套接字 WinSock 的I/O模型介绍 select 模型 WSAAsyncSelect 模型,8.1 套接字的阻塞和非阻塞操作,阻塞,阻塞的accept()操作,非阻塞的recv()操作,套接字I/O模型,问题:套接字何时可以进行读写等操作? Winsock2提供5种I/O模型 选择模型(select Model) 异步选择模型(WSAAsyncSelect Model) 事件选择模型(WSAEventSelect Model) 重叠模型(Overlapped Model) 完成端口模型(Complet

2、ion Port Model),非阻塞模式,WinSock给异步模式提供了五种I/O操作模型,可以灵活的用于各类应用需求 非阻塞模式套接字除具备阻塞套接字已有的各项优点之外,还进行了少许扩充,功能更强。,决定了,就用非阻塞的! How?,ioctlsocket()函数设置阻塞/非阻塞,创建套接字后,要将套接字设置为非阻塞,函数: int ioctlsocket( SOCKET s, long cmd, u_long FAR *argp ); 用于设置和获取与套接字相关的操作参数。 参数 s: 套接字描述符。 cmd: 对套接字s的操作命令。 argp:指向cmd命令所带参数的指针。 成功返回0

3、,否则,返回SOCKET_ERROR。,cmd FIONBIO:允许或禁止套接字s的非阻塞模式。 argp is zero,禁止非阻塞模式; argp is nonzero,允许非阻塞模式; 当一个套接字建立时,默认为阻塞模式; FIONREAD:确定套接字s可读入的数据量。argp 指向一个无符号长整型。 如果s是SOCKET_STREAM类型,则FIONREAD返回在一次recv()中所接收的所有数据量。 如果s是SOCK_DGRAM 型,则FIONREAD返回套接字上排队的第一个数据报大小。,ioctlsocket使用举例,unsigned long mode=0; /禁止非阻塞 ioc

4、tlsocket(sockfd,FIONBIO,阻塞与非阻塞通信小结 通信包括阻塞和非阻塞两种模式。在网络编程时,选择通信模式是一件很重要的事情。对于不同的协议,阻塞通信和非阻塞通信有不同的表现。 对于UDP协议而言,由于UDP没有发送缓存,因此所有UDP协议即使在阻塞模式下也不会发生阻塞。 对于面向连接的协议,在连接建立阶段,阻塞与非阻塞也表现不一。在阻塞模式下,如果没有连接请求到达,则等待连接调用将阻塞直到有连接请求到达;但在非阻塞模式下,如果没有连接请求到达,等待连接调用将直接返回。,在连接建立阶段,不管是阻塞模式还是非阻塞模式,发起连接请求的一方总是会使调用它的进程阻塞,阻塞间隔最少等

5、于到达服务器的一次往返时间。 通信模式对应用程序的设计方法也有直接的影响。在非阻塞模式下,应用程序必须不断地轮询是否有数据到达或有连接请求到达。 这种轮询的方式耗费的CPU资源较大,要尽可能避免使用,而在阻塞模式下则不存在这一问题,但其缺点是进程或线程在执行I/O操作时将被阻塞而不能执行其他的工作,因此在单进程或单线程应用中不能使用这种模式。 在多线程应用中比较适合采用阻塞模式,一个线程被阻塞不影响其他线程的工作。,8.2 套接字的I/O模型,套接字I/O模型,套接字处于非阻塞模式时,何时可以读/写套接字? 使用套接字I/O模型来确定 Winsock2提供5种I/O模型 选择模型(select

6、 Model) 异步选择模型(WSAAsyncSelect Model) 事件选择模型(WSAEventSelect Model) 重叠模型(Overlapped Model) 完成端口模型(Completion Port Model),五种I/O模型的概述,选择模型:程序自发select查询多个套接字状态 异步选择模型:套接字有事件,通知指定窗口程序 事件选择模型:套接字有事件,通知指定事件对象 重叠模型:提交多个I/O请求,完成后通知事件或执行指定程序 完成端口模型:创建指定数目的线程,组成线程池,池内的空闲线程对提交的I/O请求逐个处理。,操作系统对套接字I/O模型的支持情况,所有Win

7、dows平台都支持套接字以阻塞或非阻塞方式工作。然而,并非每种平台都支持每一种I/O模型。在当前版本的Windows CE 中,仅提供了一个I/O模型。,套接字的select模型,select模型,select模型是WinSock中最常见的I/O模型。 程序调用select函数自发查询一个或多个套接字的状态,判断套接字上是否存在数据,或者能否向一个套接字写入数据。 既能防止应用程序在套接字处于阻塞模式时,在一次I/O操作后被阻塞,同时也能防止在套接字处于非阻塞模式时,产生WSAEWOULDBLOCK错误。,select函数如下: int select( intnfds,/描述符值域,Windo

8、ws下可忽略 fd_set *readfds,/检查可读性集合 fd_set *writefds,/检查可写性集合 fd_set *exceptfds,/检查错误集合 const struct timeval *timeout/等待时间);,select函数如下: int select( intnfds,/描述符值域,Windows下可忽略 fd_set *readfds,/检查可读性集合 fd_set *writefds,/检查可写性集合 fd_set *exceptfds,/检查错误集合 const struct timeval *timeout/等待时间); fd_set 数据类型代表着

9、一系列特定套接字的集合。 typedef struct fd_set u_int fd_count; /反映fd_array的实际元素数量 SOCKET fd_arrayFD_SETSIZE; / 套接字句柄数组 fd_set;,此函数用于检测一个或多个套接字的状态。套接字的状态包括可读、可写、出错。 需要检测状态的套接字集合由一个fd_set结构指示,分别为readfds,writefds,exceptfds(不能同时为NULL)。 参数timeout指向timeval结构,用于指定select等待I/O操作完成的时间。如timeout是一个空指针,select调用会无限期地,直到至少有一个

10、套接字满足条件。,timeval结构的格式为: struct timeval long tv_sec;/秒(s) long tv_usec;/毫秒(ms) ; select函数调用失败,返回SOCKET_EEROR;超时返回0;成功返回所有集合中满足条件的套接字数量。同时传入的套接字集合被更新,集合中保留满足条件的套接字,readfds集合包括等待可读性检查的套接口: 有数据可以读入。 连接已经关闭、重设或中止。 侦听套接字调用了listen(),若有连接请求到达,那么accept函数调用会成功。 writefds集合包括等待可写性检查的套接口: 未处于connect()调用中,意味着send

11、()和sendto()调用可以无阻塞的发出数据。 如果正在connect()连接(非阻塞),可写性意味着连接顺利建立。 exceptfds集合包括满足下述任何一个条件套接字: 假如套接口正在进行connect()(非阻塞),则连接试图的失败将会表现在exceptfds参数中。 有带外(Out-of-band,OOB)数据可供读取。,readfds,writefds,exceptfds,套接字集合,有事情发生,有未决的连接请求,数据可读,连接关闭/重启/中断,连接成功(connect),可写数据,连接失败(connect),带外数据可读,选择(select)模型处理方式,select(),假定想

12、测试一个套接字是否“可读”,必须将该套接字增添到readfds集合,再等待select函数完成。 select完成之后,必须判断该套接字是否仍在readfds集合中,若在,便表明该套接字“可读”,可从它上面读取数据。 Winsock提供了下列宏操作,对fd_set套接字集合进行处理与检查: FD_CLR(s, *set):从set中删除套接字s。 FD_ISSET(s, *set):检查s是否在set集合中,若是返回TRUE,否则返回FALSE。 FD_SET(s, *set):将套接字s加入集合set。 FD_ ZERO( * set ):将set初始化成空集合,使用select模型的编程步

13、骤: 建立fd_set集合s,用来存放待使用的套接字。 将套接字添加到集合s中。 确定要检查的套接字集合Xi(1= i =3)。 使用FD_ZERO宏,初始化Xi 。 使用FD_SET宏,根据需要将套接字句柄添加到Xi中 调用select函数 根据select函数的返回值进行处理,当成功返回时,判断s中套接字是否在Xi中,并进行相应处理 回到4,select模型实例分析,select模式实例,实现一个阻塞的TCP套接字服务器,端口5150; 主线程不断的接受客户端的连接; 工作线程利用 select() 函数不断检查是否有数据可以读取;有则读取,原样发送给客户端。,select模式实例,/ 头

14、文件 #include stdafx.h #include winsock2.h #include stdio.h #define PORT 5150 #define MSGSIZE 1024 #pragma comment(lib, ws2_32.lib) int g_iTotalConn = 0; /全局计数器 SOCKET g_CliSocketArrFD_SETSIZE; /全局通信套接字 DWORD WINAPI WorkerThread(LPVOID lpParam); /声明处理数据接收的线程函数,int main(int argc, char* argv) WSADATA ws

15、aData; SOCKET sListen, sClient; SOCKADDR_IN local, client; int iAddrSize = sizeof(SOCKADDR_IN); DWORD dwThreadId; / 初始化Winsock动态链接库 WSAStartup(0 x0202, ,/ 绑定到IP和端口 local.sin_family = AF_INET; local.sin_addr.S_un.S_addr = htonl(INADDR_ANY); local.sin_port = htons(PORT); bind(sListen, (sockaddr*),whil

16、e (TRUE) / 接受客户端连接 sClient = accept(sListen, (sockaddr*) ,DWORD WINAPI WorkerThread(LPVOID lpParam) int i; fd_set fdread; /定义一个FD集合,用于测试read int ret; struct timeval tv = 1, 0; /1秒的间隔 char szMessageMSGSIZE;/接收缓冲区 while (TRUE) FD_ZERO( ,/ 我们只关心这些套接字里面有没有数据可以read ret = select(0, ,if (ret = 0 | (ret = S

17、OCKET_ERROR /最后一个满足条件的套接字放到i,将i、 g_iTotalConn减一, else /if (ret=) / ret0,没出错,收到ret个字节 szMessageret = /0; send(g_CliSocketArri, szMessage, strlen(szMessage), 0); ,select模型的优点:可以在单线程内管理多个套接字,最大套接字数量取决于FD_SETSIZE的大小,Winsock2.h中定义为64,用户也可自行定义,但不能超过1024。 缺点:调用select前后对所有套接字都要进行遍历操作,以便设置和检查。当FD_SETSIZE太大时,

18、服务器性能明显下降。,最通俗浅显的“IO模式”解析,老陈有几个在外地工作的女儿,不能经常回来,老陈和她们通过信件联系。她们的信会被邮递员投递到老陈的信箱里。 情况与Socket模型非常类似。,select模型,老陈非常想看到女儿的信。以至于他每隔10分钟就下楼检查信箱,看是否有女儿的信,在这种情况下,“下楼检查信箱”然后回到楼上耽误了老陈太多的时间,以至于老陈无法做其他工作。 select模型和老陈的这种情况非常相似:周而复始地去检查.如果有数据.接收/发送.,套接字的WSAAsyncSelect模型,WSAAsyncSelect模型,WSAAsyncSelect模型是WinSock中另一个常

19、用的异步I/O模型。 该模型可在套接字上接收以Windows消息为基础的网络事件通知。 调用WSAAsyncSelect函数自动将套接字设置为非阻塞模式,并向WinSock DLL注册一个或多个感兴趣的网络事件,同时提供接收通知时使用的窗口句柄,当注册的网络事件发生时,对应的窗口将收到一个基于消息的通知。,WSAAsyncSelect函数如下: int WSAAPI WSAAsyncSelect( SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent );,s为需要事件通知的套接字,hWnd为接收消息的窗口句柄,wMsg为要接收的消息,lEve

20、nt为掩码,指定应用程序感兴趣的网络事件组合,用于WSAAsyncSelect函数的网络事件类型,用法举例,要接收读写通知: #define WM_SOCKET WM_USER + 101 int nResult = WSAAsyncSelect(s,hWnd,WM_SOCKET,FD_READ|FD_WRITE); if(nResult=SOCKET_ERROR) /错误处理 ,问题1:对监听套接字和通信套接字应如何设置消息通知?设置哪些事件? 监听套接字: WSAAsyncSelect(sListen,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE); 通信套接字: W

21、SAAsyncSelect(sComm,hWnd,WM_SOCKET,FD_READ|FD_WRITE|FD_CLOSE);,注意: 多个事件务必在套接字上一次注册! 一旦在某个套接字上允许了事件通知,除非以后明确调用closesocket(),或者由应用程序针对该套接字调用了WSAAsyncSelect,从而更改了注册的网络事件类型,否则的话,事件通知会永远有效! 若将lEvent参数设为0,效果相当于停止在套接字上进行的所有网络事件通知。,只接受一个消息设置.下面的代码将不会工作;第二个调用将会使第一次调用的作用失效,只有FD_WRITE会通过wMsg2消息通知到。 1、 WSAAsync

22、Select(s, hWnd, wMsg1, FD_READ);2、 WSAAsyncSelect(s, hWnd, wMsg2, FD_WRITE); 如果要取消所有的通知,也就是指出Windows Sockets的实现不再在套接口上发送任何和网络事件相关的消息,则lEvent应置为0. WSAAsyncSelect(s, hWnd, 0, 0);,应用程序在一个套接字上成功调用了WSAAsyncSelect之后,应用程序会在与hWnd窗口句柄参数对应的窗口处理函数中,以Windows消息的形式,接收网络事件通知。 窗口处理函数定义如下:,LRESULT CALLBACK WindowPro

23、c(HWND hwhd, UINT uMsg, WPARAM wParam, LPARAM IParam) 参数: hwnd:指向窗口的句柄。 uMsg:指定消息类型。 wParam:指定消息的附加信息。该参数的内容与UMsg参数值有关。 IParam:指定消息的附加信息。该参数的内容与uMsg参数值有关。 返回值:返回值就是消息处理结果,它与发送的消息有关。,wParam, IParam参数在uMsg WM_SOCKET时的含义: wParam指定发生网络事件的套接字。 IParam指定发生的网络事件和错误代码。 其中高字位指出网络错误。采用宏:WSAGETSELECTERROR,可用它返回

24、高字节包含的错误信息,如下: #define WSAGETSELECTERROR(lParam) HIWORD(lParam) 低字位指出发生的网络事件,采用宏:WSAGETSELECTEVENT,返回网络事件 #define WSAGETSELECTEVENT(lParam) LOWORD(lParam),收到 FD_READ 事件通知的情况: (1)调用 WSAAsyncSelect ()对 socket 设定 FD_READ 事件时,接收缓冲区中已有数据。 (2)接收缓冲区由空变为有数据 (3)调用 recv() 或 recvfrom ()从 接收缓冲区读取数据时没有读完。,收到FD_W

25、RITE事件通知的情况: 使用connect或WSAConnect,一个套接字首次建立了连接。 使用accept或WSAAccept,套接字被接受以后。 若send、WSASend、sendto或WSASendTo操作失败,返回了WSAEWOULDBLOCK错误,而且缓冲区的空间变得可用。 应用程序,自收到首条FD_WRITE消息开始,便应认为自己必然能在一个套接字上发出数据,直至一个send、WSASend、sendto或WSASendTo返回套接字错误WSAEWOULDBLOCK。经过了这样的失败以后,系统要再用另一条FD_WRITE通知应用程序再次发送数据。,使用WSAAsyncSele

26、ct模型编程步骤: Winsock初始化 自定义WM_SOCKET 消息 创建窗口,必须有窗体才有消息处理 创建套接字 调用WSAAsyncSelect()定义需要响应的Socket动作 编写WindowProc()完成Socket相关动作处理,示例:WSAAsyncSelect模式的服务器,#pragma once #include #include #define PORT 5150 #define MSGSIZE 1024 #define WM_SOCKET WM_USER+0 #pragma comment(lib, ws2_32.lib) LRESULT CALLBACK WndPr

27、oc(HWND, UINT, WPARAM, LPARAM);,int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) static TCHAR szAppName = _T(AsyncSelect Model); HWND hwnd ; MSG msg ; WNDCLASS wndclass ; /此处省略了 wndclass 的风格定义 if (!RegisterClass( ,hwnd = CreateWindow (szAppName, / window class name TEXT (AsyncSelect Model), / window caption WS_OVERLAPPEDWINDOW, / window style CW_USEDEFAULT, / initial x position CW_USEDEFAULT, / initial y position

温馨提示

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

评论

0/150

提交评论