WinSock 异步I/O模型
如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的。 Windows操作系统提供了五种I/O模型,分别是选择(select)模型,异步选择(WSAAsyncSelect)模型,事件选择(WSAEventSelect)模型,重叠I/O(Overlapped I/O)模型,完成端口(Completion Port)模型。
so,接下来就一一介绍这些模型的使用方法:
1、选择(select)模型
- 选择(select)模型是Winsock中最常见的 I/O模型。核心便是利用 select 函数,实现对 I/O的管理。 利用 select 函数来判断某Socket上是否有数据可读,或者能否向一个套接字写入数据,防止程序在Socket处于阻塞模式中时,在一次 I/O 调用(如send或recv、accept等)过程中,被迫进入“锁定”状态; 可以同时等待多个套接字,当某个或者多个套接字满足可读写条件时,通知应用程序调用输入或者输出函数进行读写。 同时防止在套接字处于非阻塞模式中时,产生WSAEWOULDBLOCK错误。它意味着请求的操作在调用期间没有时间完成。举个例子来说,假如在系统的输入缓冲区中,尚不存在“待决”的数据,那么recv(接收数据)调用就会返回WSAEWOULDBLOCK错误。通常,我们需要重复调用同一个函数,直至获得一个成功返回代码。
- select:select 的函数原型如下:
- int select( __in int nfds,
- __in_out fd_set* readfds,
- __in_out fd_set* writefds,
- __in_out fd_set* exceptfds,
- __in const struct timeval* timeout );
- 其中,第一个参数nfds会被忽略。之所以仍然要提供这个参数,只是为了保持与Berkeley套接字兼容。 后面看到有三个 fd_set类型的参数: 一个用于检查可读性(readfds), 一个用于检查可写性(writefds), 一个用于例外数据(exceptfds)。
- fd_set 结构: fd_set 结构的定义如下:
- typedef struct fd_set {
- u_int fd_count;
- SOCKET fd_array[FD_SETSIZE]; } fd_set;
- #define FD_SETSIZE 64 所以 fd_set 结构中最多只能监视64个套接字。
- fdset 代表着一系列特定套接字的集合。 其中, readfds 集合包括符合下述任何一个条件的套接字:
- ● 有数据可以读入。
- ● 连接已经关闭、重设或中止。
- ● 假如已调用了listen,而且一个连接正在建立,那么accept函数调用会成功。
- writefds 集合包括符合下述任何一个条件的套接字:
- ● 有数据可以发出。
- ● 如果已完成了对一个非锁定连接调用的处理,连接就会成功。
- exceptfds 集合包括符合下述任何一个条件的套接字:
- ● 假如已完成了对一个非锁定连接调用的处理,连接尝试就会失败。
- ● 有带外(Out-of-band,OOB)数据可供读取。
- 举个例子,假设我们想测试一个套接字是否“可读”,必须将自己的套接字增添到readfds集合中,然后调用 select 函数并等待其完成。select 完成之后,再次判断自己的套接字是否仍为 readfds 集合的一部分。若答案是肯定的,则表明该套接字“可读”,可立即着手从它上面读取数据。 在三个参数中(readfds、writefds 和 exceptfds),任何两个都可以是空值( NULL); 但是,至少有一个不能为空值!在任何不为空的集合中,必须包含至少一个套接字句柄; 否则, select 函数便没有任何东西可以等待。最后一个参数 timeout 对应的是一个指针,它指向一个timeval 结构,用于决定select 最多等待 I/O操作完成多久的时间。如 timeout 是一个空指针,那么 select 调用会无限期地“锁定”或停顿下去,直到至少有一个描述符符合指定的条件后结束
- timeval 结构:对 timeval 结构的定义如下: tv_sec 字段以秒为单位指定等待时间; tv_usec 字段则以毫秒为单位指定等待时间。 1秒 = 1000毫秒 若将超时值设置为(0 , 0),表明 select 会立即返回,出于对性能方面的考虑,应避免这样的设置。
- selec函数返回值与用法:
- select 函数返回值: select 成功完成后,会在 fdset 结构中,返回刚好有未完成的 I/O操作的所有套接字句柄的总量。 若超过 timeval 设定的时间,便会返回0。若 select 调用失败,都会返回 SOCKET_ERROR,应该调用 WSAGetLastError 获取错误码! 用 select 对套接字进行监视之前,必须将套接字句柄分配给一个fdset的结构集合,之后再来调用 select,便可知道一个套接字上是否正在发生上述的 I/O 活动。
- Winsock 提供了下列宏操作,可用来针对 I/O活动,对 fdset 进行处理与检查:
- ● FD_CLR(s, *set):从set中删除套接字s。
- ● FD_ISSET(s, *set):检查s是否set集合的一名成员;如答案是肯定的是,则返回TRUE。
- ● FD_SET(s, *set):将套接字s加入集合set。
- ●FD_ZERO( * set):将set初始化成空集合。
例如,假定我们想知道是否可从一个套接字中安全地读取数据,同时不会陷于无休止的“锁定”状态,便可使用 FDSET 宏,将自己的套接字分配给 fdread 集合,再来调用 select。要想检测自己的套接字是否仍属 fdread 集合的一部分,可使用 FD_ISSET 宏。采用下述步骤,便可完成用 select 操作一个或多个套接字句柄的全过程: 1) 使用FDZERO宏,初始化一个fdset对象; 2) 使用FDSET宏,将套接字句柄加入到fdset集合中; 3) 调用 select 函数,等待其返回……select 完成后,会返回在所有 fdset 集 合中设置的套接字句柄总数,并对每个集合进行相应的更新。 4) 根据 select的返回值和 FDISSET宏,对 fdset 集合进行检查。 5) 知道了每个集合中“待决”的 I/O操作之后,对 I/O进行处理,然后返回步骤 1 ),继续进行 select 处理。 select 函数返回后,会修改 fdset 结构,删除那些不存在待决 I/O 操作的套接字句柄。 这正是我们在上述的步骤 ( 4 ) 中,为何要使用 FDISSET 宏来判断一个特定的套接字是否仍在集合中的原因。
- 总结一下,select的优势与不足:
- 优势: 1.可以同时对多个建立起来的套接字进行有序的管理。可以防止应用程序在一次I/O调用过程中,使阻塞模式套接字被迫进入阻塞状态;使非阻塞套接字产生WASEWOUBDBLOCK错误。 2.selcet()函数好像就是一个消息中心,当消息到来时,通知应用程序接收和发送数据。这使得Windows Sockets应用程序开发人员可以把精力更多集中在如何处理数据的发送和接收上。
- 不足: 当完成一次I/O操作经历了两次Windows Sockets函数的调用。例如,当接收对方数据时,第一步,调用selcet()函数等待该套接字的满足条件。第二步,调用recv()函数接收数据。这种结果与一个阻塞模式的套接字上调用recv()函数是一样的。因此,使用select()函数的Windows Sockets程序,其效率可能受损。因为,每一个Windows Sockets I/O调用都会经过该函数,因而会导致严重的CPU额外负担。在CPU使用效率不是关键因素时,这种效率可以接受。但是,当需要高效率时,肯定会产生问题。
WinSock 异步I/O模型的更多相关文章
- WinSock 异步I/O模型 转载
如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的.Windows操作系统提供了五种I/O模型,分别是: ■ 选择(select):■ 异步选择(WSAAsyncSelect) ...
- WinSock 异步I/O模型-3
重叠I/O(Overlapped I/O) 在 Winsock 中,重叠 I/O(Overlapped I/O)模型能达到更佳的系统性能,高于之前讲过的三种.重叠模型的基本设计原理便是让应用程序使用一 ...
- WinSock 异步I/O模型-1
异步选择(WSAAsyncSelect):异步选择基本定义 异步选择(WSAAsyncSelect)模型是一个有用的异步 I/O 模型.利用这个模型,应用程序可在一个套接字上,接收以 Windows ...
- WinSock 异步I/O模型-2
事件选择(WSAEventSelect): WSAEventSelect模型是Windows Sockets提供的另外一个有用的异步I/O模型.该模型允许一个或多个套接字上接收以事件为基础的网络事件通 ...
- 阻塞与非阻塞、同步与异步 I/O模型
I/O模型 Linux 下的五种I/O模型 阻塞I/O(blocking I/O) 非阻塞I/O (nonblocking I/O) I/O复用(select 和poll) (I/O multiple ...
- 【转】深入浅出异步I/O模型
转自:http://pengpeng.iteye.com/blog/868643 从上篇文章的介绍我们知道linux内核根据TCP/IP网络模型,给我们隐藏了传输层以下的网络传输细节,我们的网络应用程 ...
- 磁盘IO的性能指标 阻塞与非阻塞、同步与异步 I/O模型
磁盘IO的性能指标 - 蝈蝈俊 - 博客园https://www.cnblogs.com/ghj1976/p/5611648.html 阻塞与非阻塞.同步与异步 I/O模型 - 蝈蝈俊.net - C ...
- 阻塞 , 非阻塞 , 同步 ,异步 , I/O模型
•阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待: •同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞:异步只需要I/O操作完成的通知,并不主动读写 ...
- Python的异步编程[0] -> 协程[1] -> 使用协程建立自己的异步非阻塞模型
使用协程建立自己的异步非阻塞模型 接下来例子中,将使用纯粹的Python编码搭建一个异步模型,相当于自己构建的一个asyncio模块,这也许能对asyncio模块底层实现的理解有更大的帮助.主要参考为 ...
随机推荐
- CEPH s3 java sdk PUT对象并在同一个PUT请求中同时设置ACL为 Public
java: http://docs.aws.amazon.com/zh_cn/AmazonS3/latest/dev/acl-using-java-sdk.html tring bucketName ...
- vue项目中对axios的二次封装
近来在使用vue重构公司m站时,使用了axios来进行数据的请求,由于项目的需要,对axios进行了二次封装,点击进入axios //引入axios import axios from 'axios' ...
- php 连接mssql
以前用的都是mysql,今天突然想用下mssql,起先用的是sql server200. 第一种方法 打开mssql.dll拓展.然后把mssql.secure_connection = off改为o ...
- MySQL出现“错误1067:进程意外终止”
1.错误描述 2.错误原因 今天,我在摸索如何利用命令查看MySQL日志,查了很多资料,大多数是通过修改my.ini文件配置.我修改了配置后,准备重启MySQL服务器,先执行了net stop mys ...
- freemarker中的split字符串分割
freemarker中的split字符串分割 1.简易说明 split分割:用来根据另外一个字符串的出现将原字符串分割成字符串序列 2.举例说明 <#--freemarker中的split字符串 ...
- WPF基础篇之连接数据库
WPF连接DB2数据库 public void ConnectionBD2Func() { //连接数据库字符串,DB2 9.5以下版本使用Data Source=Test,否则查询找不到数据库.DB ...
- ssm+maven多模块项目整合
我的项目一共会分为4个模块:entity.dao.service和web 一.创建父模块 填写GroupId与ArtifactId 填写项目名称和项目保存路径 因为是父模块所以src包可以删除 二.创 ...
- 游戏中实现粒子碰撞,纯java
package com.totoo.TouhouMassLight;import android.content.Context;import android.graphics.Bitmap;impo ...
- mini-css-extract-plugin 的用法(webpack4)
今天在使用webpack的extract-text-webpack-plugin插件提取单独打包css文件时,报错,说是这个插件要依赖webpack3的版本. 后面查了一下,webpack4得使用mi ...
- 【BZOJ2342】双倍回文(回文树)
[BZOJ2342]双倍回文(回文树) 题面 BZOJ 题解 构建出回文树之后 在\(fail\)树上进行\(dp\) 如果一个点代表的回文串长度为\(4\)的倍数 并且存在长度为它的一半的回文后缀 ...