当前位置: 首页 > >

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文库加价一倍】


?


?



转载于:https://www.cnblogs.com/fullsail/archive/2012/08/12/2634336.html



友情链接: