zoukankan      html  css  js  c++  java
  • Windows,Linux的select函数功能差异

    Windows,Linux的select函数功能差异

    感谢主,Windows当年也实现了select函数,这让我们的跨平台大业至少顺畅了一节。但由于Windows渗入骨髓的叛逆心理,他总要和UNIX的实现保持一些差别,让你无可奈何。首先是Windows的select函数的参数接口设计和Linux下有较大差别,这个在我的《设计极其糟糕的select函数》就讨论过,相对而言,在参数设计上,Windows的设计明显好于Linux。这次我们聊聊他们的功能差异。

    1          无句柄等待触发时的处理的差异

    最近的新的重构代码,发现在Windows下,程序的CPU很高,测试发现select函数并没有等待,return-1,我们的代码原来使用的是rector模式,里面会用select当作反应器,处理IO事件,在没有IO事件时当作sleep。但我们的业务服务器没有任何要处理的IO句柄,所以就相当于调用的是

    select(0,NULL,NULL,NULL,wait_timeval);

    这种方式在Linux下就相当于sleep,而Windows下却之间返回了-1,认为你传递的参数错误。查询了一下MSDN发现有如下说明。

    Microsoft MSDN:
    
    Any two of the parameters, readfds, writefds, or exceptfds, can be given as null. At least one must be non-null, and any non-null descriptor set must contain at least one handle to a socket.

    所以在Windows下,希望将select作为sleep的方法是不可行的,

    修正问题的方法也很简单,我们有一层OS适配层,在其中对于select函数做了一下重新包装,在3个句柄数组都为NULL的时候,直接调用::Sleep,这个就OK了。

    值得注意的是ACE在这块处理上也没有解决这个问题,也可以算是一个ACE的陷阱。但由于ACE的Rector包装内部的notify队列会注册一个句柄到select中(奇怪的是我已经使用了ACE_HAS_REACTOR_NOTIFICATION_QUEUE宏,这个宏应该让notify使用消息队列而不是网络通信方式),所以默认情况下你不会发现这个问题,当你关闭notify队列时(reactor的open函数参数),问题也一样出现了。

    2          非阻塞连接失败触发的差异

    放假前最后一天,yunfeiyang突然告诉我说通信程序作为Windows下没有进行重连处理,一起定位了一下,发现Windows下需要非阻塞connect其他服务器连接在连接失败后就没有任何事件触发。

    仔细看了看代码,我们的代码是在connect失败后,如果返回错误是EWOULDBLOCK后,就认为成功发起了非阻塞连接。等待写事件和读事件,如果连接成功,如果连接失败,应该会触发读写事件(我的代码优先处理读事件)。这个和《UNIX网络编程:卷1》的描述一致,而且在Linux下测试也正常。但事实是在Windows下,非阻塞连接失败后,读写事件都没有触发。

    突然想起来,我最早的通信服务器是使用ACE作为底层的,当时的测试过没有这个问题。于是翻出了当时测试的小例子开始调试。发现连接失败后,ACE的ACE_Select_Reactor可以触发handle_close事件。于是有点晕了,再进一步检查代码发现在ACE注册事件的时候有这样一段。

    //注册事件时的代码:
    // EXCEPT (and CONNECT on Win32) flag will place the handle in
    // the except set.
          if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::EXCEPT_MASK)
    #if defined (ACE_WIN32)
              || ACE_BIT_ENABLED (mask, ACE_Event_Handler::CONNECT_MASK)
    #endif /* ACE_WIN32 */
              )
            {
              (handle_set.ex_mask_.*ptmf) (handle);
            }

    其针对WIN32平台有特殊处理,马上去翻了翻MSDN,发现果然,针对异常事件的句柄描述如下:果然微软平台的处理和Linux不一样,对于非阻塞连接失败,触发的是异常事件。

    Microsoft MSDN:
    
    exceptfds:
    
        If processing a connect call (nonblocking), connection attempt failed.
    
        OOB data is available for reading (only if SO_OOBINLINE is disabled).

    另外糟糕的是,这种问题无法在底层屏蔽(因为底层根本不知道你触发某个事件的目的是什么),这种差异只能在上层封装中解决。

    如果有时间会总结一些Linux+Windows跨平台的文章,估计大标题可以写成狗日的微软。

    【本文作者是雁渡寒潭,本着自由的精神,你可以在无盈利的情况完整转载此文档,转载时请附上BLOG链接:http://www.cnblogs.com/fullsail/ 或者http://blog.csdn.net/fullsail,否则每字一元,每图一百不讲价。对Baidu文库加价一倍】

  • 相关阅读:
    BZOJ3752 : Hack
    XIV Open Cup named after E.V. Pankratiev. GP of SPb
    XIII Open Cup named after E.V. Pankratiev. GP of Ukraine
    BZOJ2087 : [Poi2010]Sheep
    BZOJ2080 : [Poi2010]Railway
    BZOJ2082 : [Poi2010]Divine divisor
    Moscow Pre-Finals Workshop 2016. National Taiwan U Selection
    XIII Open Cup named after E.V. Pankratiev. GP of Asia and South Caucasus
    XIII Open Cup named after E.V. Pankratiev. GP of Azov Sea
    XIII Open Cup named after E.V. Pankratiev. GP of SPb
  • 原文地址:https://www.cnblogs.com/fullsail/p/2634336.html
Copyright © 2011-2022 走看看