zoukankan      html  css  js  c++  java
  • WinSock异步IO模型之Select

    如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的。
    Windows操作系统提供了五种I/O模型,分别是:

    ■ 选择(select);
    ■ 异步选择(WSAAsyncSelect);
    ■ 事件选择(WSAEventSelect);
    ■ 重叠I/O(Overlapped I/O);
    ■ 完成端口(Completion Port) 。

    每一种模型适用于一种特定的应用场景。程序员应该对自己的应用需求非常明确,
    综合考虑到程序的扩展性和可移植性等因素,作出自己的选择。
    ==============================================
    █ 选择(select)模型是Winsock中最常见的 I/O模型。核心便是利用 select 函数,实现对 I/O的管理!
    利用 select 函数来判断某Socket上是否有数据可读,或者能否向一个套接字写入数据,防止程序在Socket处于阻塞模式中时,
    在一次 I/O 调用(如send或recv、accept等)过程中,被迫进入“锁定”状态;同时防止在套接字处于非阻塞模
    式中时,产生WSAEWOULDBLOCK错误。

    █ 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 结构的定义如下:
    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 结构的定义如下:
    tv_sec 字段以秒为单位指定等待时间;
    tv_usec 字段则以毫秒为单位指定等待时间。
    1秒 = 1000毫秒

    若将超时值设置为(0 , 0),表明 select 会立即返回,出于对性能方面的考虑,应避免这样的设置。

    █ 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 处理。

  • 相关阅读:
    数组从文件中读取(接上问题)
    符合json格式要求的字符串转化为json字符串
    json-lib --->入门
    XStream-->别名;元素转属性;去除集合属性(剥皮);忽略不需要元素
    Ajax案例5-->省市联动
    Ajax案例4-->接收后台传递的XML数据
    Ajax案例3-->判断用户名是否被占用
    Ajax案例2-->POST请求
    Ajax案例1-->GET请求
    SecureCRT连接VMWare中的linux系统相关配置
  • 原文地址:https://www.cnblogs.com/haoyuanyuan/p/3284949.html
Copyright © 2011-2022 走看看