zoukankan      html  css  js  c++  java
  • 选择模型

        选择(select)模型是Winsock中最常见的 I/O模型。核心便是利用 select 函数,实现对 I/O的管理!利用 select 函数来判断某Socket上是否有数据可读,或者能否

    一个套接字写入数据,防止程序在Socket处于阻塞模式中时,在一次 I/O 调用(如send或recv、accept等)过程中,被迫进入“锁定”状态;同时防止在套接字处于非

    阻塞模式中时,产生WSAEWOULDBLOCK错误。

    select 的函数原型如下:

        int select(

            __in int nfds,                                  //会被忽略,只是为了保持与Berkeley套接字兼容

            __in_out fd_set* readfds,                //检查可读性

            __in_out fd_set* writefds,               //检查可写性

            __in_out fd_set* exceptfds,            //例外数据

            __in const struct timeval* timeout    //超时时间

       );

       其中,fd_set的结构定义为:

        typedef struct fd_set {

            u_int fd_count;

            SOCKET fd_array[FD_SETSIZE];  //#define FD_SETSIZE      64,故最多可以监视64个套接字

        } fd_set;

        下面,我们来看看那三个输入输出参数各表示什么意思

        readfds:readfds 集合包括符合下述任何一个条件的套接字

               1、有数据可以读入。

               2、连接已经关闭、重设或中止。

               3、假如已调用了listen,而且一个连接正在建立,那么accept函数调用会成功。

        writefds:writefds 集合包括符合下述任何一个条件的套接字

               1、有数据可以发出。

               2、 如果已完成了对一个非锁定连接调用的处理,连接就会成功。

        exceptfds:exceptfds 集合包括符合下述任何一个条件的套接字

               1、假如已完成了对一个非锁定连接调用的处理,连接尝试就会失败。

               2、有带外(Out-of-band,OOB)数据可供读取。

        在这三个参数中(readfds、writefds 和 exceptfds),任何两个都可以是空值( NULL);但是,至少有一个不能为空值!在任何不为空的集合中,必须包含至少一

    个套接字句柄;否则, select 函数便没有任何东西可以等待。最后一个参数 timeout 对应的是一个指针,它指向一个timeval 结构,用于决定select 最多等待 I/O操作

    完成多久的时间。如 timeout 是一个空指针,那么 select 调用会无限期地“锁定”或停顿下去,直到至少有一个描述符符合指定的条件后结束。

        timeval 结构的定义如下:

             tv_sec 字段以秒为单位指定等待时间;

             tv_usec 字段则以毫秒为单位指定等待时间。

             1秒 = 1000毫秒

        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初始化成空集合。

        select 函数返回后,会修改 fdset 结构,删除那些不存在待决 I/O 操作的套接字句柄。

        select函数具体流程步骤如下:

            1、使用FDZERO宏,初始化一个fdset对象。

            2、使用FDSET宏,将套接字句柄加入到fdset集合中。

            3、调用 select 函数,等待其返回……select 完成后,会返回在所有 fdset 集合中设置的套接字句柄总数,并对每个集合进行相应的更新。

            4、根据 select的返回值和 FDISSET宏,对 fdset 集合进行检查。

            5、知道了每个集合中“待决”的 I/O操作之后,对 I/O进行处理。

            6、然后返回步骤1,继续进行 select 处理。

        在代码的实现中,我封装了一个SelectSocket函数用于对select函数的操作,该函数定义如下:

    BOOL SelectSocket(SOCKET s, int iTimeOut, BOOL bRead)
    {
        ASSERT(s != INVALID_SOCKET);
        fd_set fd;
        FD_ZERO(&fd);
        FD_SET(s, &fd);
        timeval time;
        time.tv_sec = iTimeOut / 1000;
        time.tv_usec = iTimeOut % 1000;
        int iFlg;
        if (bRead)
        {
            iFlg = select(0, &fd, NULL, NULL, &time);
        }
        else
        {
            iFlg = select(0, NULL, &fd, NULL, &time);
        }
        if (iFlg <= 0)
        {
            return FALSE;
        }
        else if (FD_ISSET(s, &fd))
        {
            return TRUE;
        }
        return FALSE;
    }

        这里我就不演示界面交互了,在我的另一篇随笔,<<异步选择模型>>中,我会用select函数实现的Client与用WSAAsyncSelect函数实现的Server进行交互,那时我

    们再看看这种模型的具体实现过程。

        http://www.cnblogs.com/venow/archive/2012/06/09/2543053.html

        

  • 相关阅读:
    JS高级——eval
    JS高级——Object.prototype成员
    JS高级——原型链
    JS高级——逻辑中断
    移动web——bootstrap媒体对象
    移动web——bootstrap如何修改原组件
    移动web——bootstrap响应式轮播图
    Leetcode题解
    位运算实现四则运算(C++实现)
    扫码登陆原理
  • 原文地址:https://www.cnblogs.com/venow/p/2543847.html
Copyright © 2011-2022 走看看