Windows,Linux的select函数功能差异

摘要:
Windows,Linux的select函数功能差异感谢主,Windows当年也实现了select函数,这让我们的跨平台大业至少顺畅了一节。但由于Windows渗入骨髓的叛逆心理,他总要和UNIX的实现保持一些差别,让你无可奈何。首先是Windows的select函数的参数接口设计和Linux下有较大差别,这个在我的《设计极其糟糕的select函数》就讨论过,相对而言,在参数设计上,Windows的设计明显好于Linux。但事实是在Windows下,非阻塞连接失败后,读写事件都没有触发。
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文库加价一倍】

免责声明:文章转载自《Windows,Linux的select函数功能差异》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Java项目的结构SpringCloudfeign的配置加载下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Mysql数据优化--DBA梳理珍藏篇

1. 优化SQL1)     通过show status了解各种sql的执行频率         show status like 'Com_%'        了解 Com_select,Com_insert 的执行次数 2)    通过Explain分析低效的sql语句 3)    建立合适的索引 4)    通过show status like '...

Fedora中你用GNOME还是KDE?

作者: Inwind  出自: http://www.linuxdiyf.com   本身在Fedora 9中用KDE。各位在Fedora用哪个桌面环境。  小点:KDE外不美观漂亮,特别是4.0出现后更能表现KDE在桌面的奢华,它有本身的窗口挨次,包罗文件,收集工具,运用挨次等,十足环境和CDE很像。  GNOME没有KDE的自带挨次多,但它最年夜的特...

VMware 安装Linux系统

VMware 增加Linux系统 1、启动VMware,进入主界面 2、点击“创建新的虚拟机”,进入创建虚拟机向导界面,建议初学者选择“典型(推荐)” 3、点击“下一步”按钮,进入“安装客户机操作系统”界面选择“安装来源”,建议初学者选择第三项,创建空白硬盘的虚拟机 如果有一定经验的话,可以选择第二项,通过“浏览”按钮选择我们Linux系统的映像文...

Linux命令(1)-创建文件

版本:centos7 1.可以使用cat创建一个新的文件   命令:cat>>filename   使用cat创建文件时,以系统默认的文件属性作为新文件的属性,并接受键盘输入作为文件的内容。输入结束时按Ctrl+d退出并保存文件。      另外,使用cat filename命令可以查看文件内容。   cat file1 file2 >&...

thinkphp数据查询方法总结select ,find,getField,query

thinkphp已经封装好了常用的查询方法,且都比较实用,对于不常用的查询框架也保留了原始查询方法query。 1 2 $Model=newModel()//实例化一个model对象没有对应任何数据表 $Model->query("select*fromthink_userwherestatus=1"); 如果刚学Thinkph...

Linux ifconfig查看网卡信息

查看所有网卡的信息ifconfig (不包括down状态的网卡) [root@mysql ~]# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.0.111 netmask 255.255.255.0 bro...