Linux系统下fd分配的方法

发表于:2014-9-01 10:14

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:lanyuliuyun    来源:51Testing软件测试网采编

  最近几天在公司里写网络通讯的代码比较多,自然就会涉及到IO事件监测方法的问题。我惊奇的发现select轮训的方法在那里居然还大行其道。我告诉他们现在无论在Linux系统下,还是windows系统下,select都应该被废弃不用了,其原因是在两个平台上select的系统调用都有一个可以说是致命的坑。
  在windows上面单个fd_set中容纳的socket handle个数不能超过FD_SETSIZE(在win32 winsock2.h里其定义为64,以VS2010版本为准),并且fd_set结构使用一个数组来容纳这些socket handle的,每次FD_SET宏都是向这个数组中放入一个socket handle,并且此过程中是限定了不能超过FD_SETSIZE,具体请自己查看winsock2.h中FD_SET宏的定义。
  此处的问题是
  若本身fd_set中的socket handle已经达到FD_SETSIZE个,那么后续的FD_SET操作实际上是没有效果的,对应socket handle的IO事件将被遗漏!!!
  而在Linux系统下面,该问题其实也是处在fd_set的结构和FD_SET宏上。此时fd_set结构是使用bit位序列来记录每一个待检测IO事件的fd。记录的方式稍微复杂,如下
  /usr/include/sys/select.h中
1 typedef long int __fd_mask;
2 #define __NFDBITS    (8 * sizeof (__fd_mask))
3 #define    __FDELT(d)    ((d) / __NFDBITS)
4
5 #define    __FDMASK(d)    ((__fd_mask) 1 << ((d) % __NFDBITS))
6
7 typedef struct
8   {
9     /* XPG4.2 requires this member name.  Otherwise avoid the name
10        from the global namespace.  */
11 #ifdef __USE_XOPEN
12     __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
13 # define __FDS_BITS(set) ((set)->fds_bits)
14 #else
15     __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
16 # define __FDS_BITS(set) ((set)->__fds_bits)
17 #endif
18   } fd_set;
19
20 #define    FD_SET(fd, fdsetp)    __FD_SET (fd, fdsetp)
  /usr/include/bits/select.h中
  1 # define __FD_SET(d, set)    (__FDS_BITS (set)[__FDELT (d)] |= __FDMASK (d))
  可以看出,在上面的过程,实际上每个bit在fd_set的bit序列中的位置对应于fd的值。而fd_set结构中bit位个数是__FD_SETSIZE定义的,__FD_SETSIZE在/usr/include/bits/typesize.h(包含关系如下sys/socket.h -> bits/types.h -> bits/typesizes.h)中被定义为1024。
  现在的问题是,当fd>=1024时,FD_SET宏实际上会引起内存写越界。而实际上在man select中对已也有明确的说明,如下
  NOTES
  An fd_set is a fixed size buffer. Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to or
  larger than FD_SETSIZE will result in undefined behavior. Moreover, POSIX requires fd to be a valid file descriptor.
  这一点包括之前的我,是很多人没有注意到的,并且云风大神有篇博文《一起 select 引起的崩溃》也描述了这个问题。
  可以看出在Linux系统select也是不安全的,若想使用,得小心翼翼的确认fd是否达到1024,但这很难做到,不然还是老老实实的用poll或epoll吧。
  扯得有点远了,但也引出了本片文章要叙述的主题,就是Linux系统下fd值是怎么分配确定,大家都知道fd是int类型,但其值是怎么增长的,在下面的内容中我对此进行了一点分析,以2.6.30版本的kernel为例,欢迎拍砖。
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号