感谢主,Windows当年也实现了select函数,这让咱们的跨平台大业至少顺畅了一节。但因为Windows渗入骨髓的叛逆心理,他总要和UNIX的实现保持一些差异,让你迫不得已。首先是Windows的select函数的参数接口设计和Linux下有较大差异,这个在个人《设计极其糟糕的select函数》就讨论过,相对而言,在参数设计上,Windows的设计明显好于Linux。此次咱们聊聊他们的功能差别。react
最近的新的重构代码,发如今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了。socket
值得注意的是ACE在这块处理上也没有解决这个问题,也能够算是一个ACE的陷阱。但因为ACE的Rector包装内部的notify队列会注册一个句柄到select中(奇怪的是我已经使用了ACE_HAS_REACTOR_NOTIFICATION_QUEUE宏,这个宏应该让notify使用消息队列而不是网络通讯方式),因此默认状况下你不会发现这个问题,当你关闭notify队列时(reactor的open函数参数),问题也同样出现了。函数
放假前最后一天,yunfeiyang忽然告诉我说通讯程序做为Windows下没有进行重连处理,一块儿定位了一下,发现Windows下须要非阻塞connect其余服务器链接在链接失败后就没有任何事件触发。测试
仔细看了看代码,咱们的代码是在connect失败后,若是返回错误是EWOULDBLOCK后,就认为成功发起了非阻塞链接。等待写事件和读事件,若是链接成功,若是链接失败,应该会触发读写事件(个人代码优先处理读事件)。这个和《UNIX网络编程:卷1》的描述一致,并且在Linux下测试也正常。但事实是在Windows下,非阻塞链接失败后,读写事件都没有触发。spa
忽然想起来,我最先的通讯服务器是使用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跨平台的文章,估计大标题能够写成狗日的微软。