linux下的select简直太奇葩了:1024限定的不只是监听的个数,还是文件描述符的最大值,注意,是值

落爺英雄遲暮 提交于 2019-12-18 03:01:15

我原来自以为对select就算不熟,基本原理和使用方法也略知一二了,做了一年多的服务器编程,好歹知道linux下的select不支持超过1024个的描述符,好歹知道可以通过内核编译来重设FD_SETSIZE,也敢大言不惭地说select函数的maxfd应该是监测的所有fd值中取最大的+1,甚至连世界上有select * from的语法都知道,结果,今天直接扎扎实实栽在了select上面了:我生生花了近2个小时来跟踪select的奇葩点。很让人痛苦的2个小时啊,那么多关联点,盘根错节揉在一块,每条支脉都显得那么无辜,实在有种拔剑四顾心茫然的感觉。不过,说起来也要感谢select,要不是它,这么让人痛苦的2个小时不知道怎么度过呢!总之,当我通过再三排除最终跟扯大肠一样扯出select的各种纠结时,脑海里不由得浮现出了一句箴言:“一切有为法,如梦幻泡影,如露亦如电,应作如是观”。善哉。

先说一下问题的表象,来源是这样的:我用客户端一次性发起超过2000个连接,等连接全部就绪后,设为非阻塞,将他们FD_SET进readset和writeset,以接收和发送消息。当然,这里我还是有点上面提到的常识的,不是一下子全部FD_SET进去,而是分批次,这里我是设成900,每次FD_ZERO之后我都设一个计数,FD_SET超过900个的socket就停止。因为每个连接做的事情很少,先发一次数据,再收一次数据就可以直接关闭,而在关闭之后就不再FD_SET相应的socket,所以理论上是可以依次处理完的。但这也是理论上,问题来了,我发现当第一批的连接(即前900个)关闭之后,后面的连接在读数据时纷纷提示:resource temporarily unavailable。一开始我以为我没处理好LT水平触发,结果搞了半天没效果,又怀疑到服务器端写数据时的处理,因为是边缘触发的,所以ET模式的EAGAIN、EWOULDBLOCK、EINTR写法重新查了好久,还是没有头绪。然后开始怀疑最大文件打开数,只是心里仍然觉得奇怪,因为能连续connect有2000次就已经说明不是打开数量限制的问题了,但我仍然ulimit -n xxxx,修改什么fs.file-max,设置Hn、sn的,syctl搞了一堆。还是搞不定。

万般无奈之下,突然鬼使神差般,把900改成1,就是说每次只让它监听一个socket上的事件,等前一个socket上的事件处理完再继续监听下一个socket。然后,奇葩点出现了,我打印出的输出信息显示当fd=1024这个socket处理完,开始监听值为1025的socket时,select立刻返回,并不理会我所设定的1秒的timeout超时设定。真的是1024限定的问题啊,我的第一反应是:应该是我没设好文件打开个数,然后我傻愣愣地重启了虚拟机。还是不行!这时我才开始怀疑select的第一个参数maxfd所代表的含义:没错啊,取所有监听的fd的最大值然后+1,网上很多教程都是这么写的啊。又开始查看FD_SET、FD_ISSE和FD_CLR的源码,没看出什么蹊跷。网上搜select的1024限制又有一堆人说应该重新编译linux内核,可是我只监听一个啊,只不过这个socket的值是1025而已。还有人专门写教程澄清说FD_SET几个值大于1024的描述符进去是可以的,可是我的就出错啊。

不过幸好我又搜到了这个http://bbs.chinaunix.net/thread-1791112-1-1.html,才解决了我的疑问。

最后,我决定放弃在linux下使用select。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!