网络编程--第3章_windows套接字io模型

上传人:ji****n 文档编号:54813468 上传时间:2018-09-19 格式:PPT 页数:78 大小:1.80MB
返回 下载 相关 举报
网络编程--第3章_windows套接字io模型_第1页
第1页 / 共78页
网络编程--第3章_windows套接字io模型_第2页
第2页 / 共78页
网络编程--第3章_windows套接字io模型_第3页
第3页 / 共78页
网络编程--第3章_windows套接字io模型_第4页
第4页 / 共78页
网络编程--第3章_windows套接字io模型_第5页
第5页 / 共78页
点击查看更多>>
资源描述

《网络编程--第3章_windows套接字io模型》由会员分享,可在线阅读,更多相关《网络编程--第3章_windows套接字io模型(78页珍藏版)》请在金锄头文库上搜索。

1、,第三章 Windows套接字I/O模型,套接字模式 选择模型(Select Model) Windows程序基本工作原理 异步选择模型(WSAAsyncSelect Model) 事件选择模型(WSAEventSelect Model) 重叠模型(Overlapped Model) 完成端口模型(Completion Port Model),1. 套接字模式,Windows套接字在两种模式下执行I/O操作:阻塞和非阻塞。在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数(比如send和recv)会一直等候下去,不会立即返回程序(即不会将控制权交还给程序),直到该函数操作完成,或出

2、错。在非阻塞模式下, Winsock函数无论如何都会立即返回。,1.1 阻塞模式,对于处在阻塞模式的套接字,我们必须多加留意,因为在一个阻塞套接字上调用任何一个Winsock API函数,都会产生相同的后果-耗费或长或短的时间“等待”。 一个典型的例子,简单的阻塞模式示例,SOCKET sock; char buff256; int done = 0; while(!done) nBytes = recv(sock,buff,65,0);if (nBytes = SOCKET_ERROR)printf(“recv failed with error %dn”,WSAGetLastError()

3、;return;DoComputationData(buff); ,假如没有数据处于“待决”状态,那么recv函数可能永远都无法返回。 只有从系统的输入缓冲区中读回点什么东西,才允许返回!,1.2 非阻塞模式,非阻塞模式的套接字在使用上稍显困难,但它在功能上是非常强大的。除具备阻塞套接字已有的各项优点之外,还进行了扩充,功能更强。 创建一个套接字,并将其置为非阻塞模式的程序示例:,SOCKET s; u_long ul=1; int nRet; s=socket(AF_INET,SOCK_STREAM,0); nRet=ioctlsocket(s,FIONBIO,(unsigned long

4、*) if (nRet=SOCKET_ERROR) /Failed to put the socket into nonblocking mode ,设置套接字工作模式ioctlsocket(),函数形式 : int ioctlsocket (SOCKET s, long cmd, u_long * argp );,功能说明: 套接字默认工作在阻塞模式,此函数设置套接字的工作模式为非阻塞或阻塞模式。,返回值: 正确调用返回0,否则将返回SOCKET_ERROR ,应用程序可以通过 WSAGetLastError()来获取具体错误的代码。,参数说明:,cmd :表示对套接字s的操作控制命令。,a

5、rgp :指向cmd命令所带指针的参数。,SOCKET s :传入参数。用于标识一个套接字的描述符。,TCP 首部格式,紧急位 URG 当 URG 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。,紧急指针字段 占 16 位。紧急指针指出在本报文段中的紧急数据的最后一个字节的序号。,ioctlsocket使用举例,unsigned long mode=0;ioctlsocket(sockfd,FIONBIO,将一个套接字置为非阻塞模式之后, Winsock API调用会立即返回。大多数情况下,这些调用都会“失败”,并返回一个WSAEWOULDB

6、LOCK错误,这意味着请求的操作在调用期间没有完成。,例如在系统的输入缓冲区中,尚不存在“待决”的数据,那么recv(接收数据)调用就会返回WSAEWOULDBLOCK错误。通常,我们需要重复调用同一个函数,直至获得一个成功返回代码。,阻塞与非阻塞通信小结 通信包括阻塞和非阻塞两种模式。在网络编程时,选择通信模式是一件很重要的事情。对于不同的协议,阻塞通信和非阻塞通信有不同的表现。,阻塞与非阻塞通信小结 对于UDP协议而言,由于UDP没有发送缓存,因此所有UDP协议即使在阻塞模式下也不会发生阻塞.,每个TCP套接口有一个发送缓冲区,可以用SO_SNDBUF套接口选项来改变这一缓冲区的大小。 当

7、应用进程调用send往套接口写数据时,内核从应用进程缓冲区中拷贝所有数据到套接口的发送缓冲区,如果套接口发送缓冲区容不下应用程序的所有数据,或者是应用进程的缓冲区大于套接口的发送缓冲区,或者是套接口的发送缓冲区中有别的数据,应用进程将被挂起。内核将不从send返回。直到应用进程缓冲区中的所有数据都拷贝到套接口发送缓冲区。 所以,从写一个TCP套接口的send调用成功返回仅仅表示我们可以重新使用应用进程缓冲区,它并不是告诉我们对方收到数据。TCP发给对方的数据,对方在收到数据时必须给矛确认,只有在收到对方的确认时,本方TCP才会把TCP发送缓冲区中的数据删除。UDP因为是不可靠连接,不必保存应用

8、进程的数据拷贝,应用进程中的数据在沿协议栈向下传递时,以某种形式拷贝到内核缓冲区,当数据链路层把数据传出后就把内核缓冲区中数据拷贝删除。因此它不需要一个发送缓冲区。写UDP套接口的send返回表示应用程序的数据或数据分片已经进入链路层的输出队列,如果输出队列没有足够的空间存放数据,将返回错误ENOBUFS.,阻塞与非阻塞通信小结 对于面向连接的协议,在连接建立阶段,阻塞与非阻塞也表现不一。在阻塞模式下,如果没有连接请求到达,则等待连接调用将阻塞直到有连接请求到达;但在非阻塞模式下,如果没有连接请求到达,等待连接调用将直接返回。在连接建立阶段,不管是阻塞模式还是非阻塞模式,发起连接请求的一方总是

9、会使调用它的进程阻塞,阻塞间隔最少等于到达服务器的一次往返时间。,通信模式对应用程序的设计方法也有直接的影响。在非阻塞模式下,应用程序必须不断地轮询是否有数据到达或有连接请求到达。这种轮询的方式耗费的CPU资源较大,要尽可能避免使用,而在阻塞模式下则不存在这一问题,但其缺点是进程或线程在执行I/O操作时将被阻塞而不能执行其他的工作,因此在单进程或单线程应用中不能使用这种模式。在多线程应用中比较适合采用阻塞模式,一个线程被阻塞不影响其他线程的工作。,阻塞和非阻塞套接字模式各存在着优点和缺点从概念的角度说,阻塞套接字更易使用。但在应付建立连接的多个套接字时,或在数据的收发量不均,时间不定时,却显得

10、极难管理。而另一方面,由于需要编写更多的代码,以便在每个Winsock调用中,对收到一个WSAEWOULDBLOCK错误的可能性加以应付,那么非阻塞套接字便显得有些难于操作。在这些情况下,可考虑使用“套接字I/O模型”,它有助于应用程序通过一种异步方式,同时对一个或多个套接字上进行的通信事件加以管理。,套接字I/O模型,套接字处于非阻塞模式时,何时可以读/写套接字? 使用套接字I/O模型Winsock2提供5种I/O模型 选择模型(Select Model) 异步选择模型(WSAAsyncSelect Model) 事件选择模型(WSAEventSelect Model) 重叠模型(Overl

11、apped Model) 完成端口模型(Completion Port Model),操作系统对套接字I/O模型的支持情况,所有Windows平台都支持套接字以阻塞或非阻塞方式工作。 然而,并非每种平台都支持每一种I/O模型。在当前版本的Windows CE 中,仅提供了一个I/O模型。,Select模型是WinSock中最常见的I/O模型。 通过调用select函数可以确定一个或多个套接字的状态,判断套接字上是否有数据,或者能否向一个套接字写入数据,或者出现意外。目的是防止应用程序在套接字处于阻塞模式中时,在一次I/O绑定调用(如send或recv)过程中,被迫进入“阻塞”状态;同时防止在套

12、接字处于非阻塞模式中时,产生WSAEWOULDBLOCK错误。,2. select模型,int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout); 此函数用于检测一个或多个套接字的状态。套接字的状态包括可读、可写、出错。,select函数,fd_set结构,#define FD_SETSIZE 64 typedef struct fd_set u_int fd_count; SOCKET fd_arrayFD_SETSIZE; fd_set;,参数说明:,

13、参数nfds会被忽略(设为0)。之所以仍然要提供这个参数,只是为了保持与早期的Berkeley套接字应用程序的兼容。,函数形式 :,参数:fd_count:已设定socket的数量fd_array:socket列表,FD_SETSIZE为最大socket数量,建议不小于64(微软建议)。,参数readfds用于检查可读性,readfds集合(读集合)包括符合下述任何一个条件的套接字: 有可以读入数据的套接字。 连接已经关闭的套接字。 如果listen已经被调用,且有连接请求到达的套接字。该套接字出现在此集合意味着accept函数调用会成功。,参数writefds用于写数据,writefds集合

14、(写集合)包括符合下述任何一个条件的套接字: 有数据可以发出的套接字。 如果已完成了对一个套接字的非阻塞连接调用的处理,那么,该套接字出现在此集合意味着连接会成功。,参数exceptfds用于例外数据,exceptfds集合(例外集合)包括符合下述任何一个条件的套接字: 有带外数据可读。 如果已完成了对一个套接字的非阻塞连接调用的处理,那么,该套接字出现在此集合意味着连接尝试失败。,参数timeout对应的是一个时间指针,它指向一个timeval结构,表示本次select()调用最长的等待时间。,struct timeval /timeval结构long tv_sec; /* seconds

15、*/long tv_usec; /* microseconds */ ;,参数: tv_sec:以秒为单位指定等待时间; tv_usec:以毫秒为单位指定等待时间,说明: tv_sec= tv_usec =0:检查完套接字描述符后立即返回; tv_sec 和tv_usec 不全为0,在等待时间内,对于被监视的套接字描述符,如果有I/O事件发生, select()调用返回,否则一直等到超时; timeout指向NULL,则对于被监视的套接字描述符,如果有I/O事件发生, select()调用才返回,否则一直等待。,函数调用成功返回所有集合中满足条件的套接字数量。同时传入的套接字集合被更新, se

16、lect() 调用将删除集合中不能进行指定操作的套接字, 集合中保留满足条件的套接字 函数调用失败,返回SOCKET_ERROR。 如超时,返回0。,返回值:,int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);,选择(select)模型处理方式,假定想测试一个套接字是否“可读”,必须将该套接字增添到readfds集合,再等待select函数完成。 select完成之后,必须判断该套接字是否仍在readfds集合中,若在,便表明该套接字“可读”,可从它上面读取数据。,select使用,使用FD_ZERO宏,初始化自己感兴趣的每一个fd_set集合。使用FD_SET宏,将要检查的套接字加入到一个集合中。 设置等待时间,对timeval中tv_sec和tv_usec字段进行设置。调用select函数。 select正确返回时,使用FD_ISSET检查一个选定的套接字是否在指定的集合中。 针对不同集合的套接字做出不同的操作。,

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 生活休闲 > 社会民生

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号