在一般系统上, 进程打开的句柄数目是1024, 但在有的系统上, 却不是这个数, 举个栗子:
yyyyyy$ ulimit -n
100001
下面,我们来看看程序:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
#include <fcntl.h>
void fun(unsigned int n)
{
struct timeval tv; // 超时时间
tv.tv_sec = 3;
tv.tv_usec = 500; // 注意单位是微秒
fd_set rdfds;
FD_ZERO(&rdfds); // 描述集初始化
int iSock = 0;
for(unsigned int i = 0; i < n; i++)
{
iSock = socket(AF_INET, SOCK_DGRAM, 0); // 让句柄泄漏
printf("iSock is %d\n", iSock);
}
if(iSock >= 0)
{
iSock = socket(AF_INET, SOCK_DGRAM, 0);
printf("iSock here is %d\n", iSock);
FD_SET(iSock, &rdfds);
printf("to select\n");
select(iSock + 1, &rdfds, NULL, NULL, &tv);
}
}
int main(int argc, char *argv[])
{
unsigned int n = 2000;
fun(n);
printf("main end\n");
return 0;
}
这个程序在一些系统上会core dump, 我们来用strace运行一下, 部分信息如下:
write(1, "iSock here is 2003\n", 19iSock here is 2003
) = 19
write(1, "to select\n", 10to select
) = 10
*** buffer overflow detected ***: strace terminated
======= Backtrace: =========
/lib64/libc.so.6(__fortify_fail+0x37)[0x7f50f3e81057]
/lib64/libc.so.6(+0x10d210)[0x7f50f3e7f210]
/lib64/libc.so.6(+0x10efc7)[0x7f50f3e80fc7]
strace[0x4040a1]
strace[0x416cfe]
strace[0x402706]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f50f3d93b35]
strace[0x402929]
======= Memory map: ========
00400000-00469000 r-xp 00000000 fd:01 535074 /usr/bin/strace
00668000-00669000 r--p 00068000 fd:01 535074 /usr/bin/strace
00669000-0066a000 rw-p 00069000 fd:01 535074 /usr/bin/strace
0066a000-0066b000 rw-p 00000000 00:00 0
00fdb000-00ffc000 rw-p 00000000 00:00 0 [heap]
7f50f3958000-7f50f396d000 r-xp 00000000 fd:01 8622 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f50f396d000-7f50f3b6c000 ---p 00015000 fd:01 8622 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f50f3b6c000-7f50f3b6d000 r--p 00014000 fd:01 8622 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f50f3b6d000-7f50f3b6e000 rw-p 00015000 fd:01 8622 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f50f3b6e000-7f50f3b70000 r-xp 00000000 fd:01 1794 /usr/lib64/libdl-2.17.so
7f50f3b70000-7f50f3d70000 ---p 00002000 fd:01 1794 /usr/lib64/libdl-2.17.so
7f50f3d70000-7f50f3d71000 r--p 00002000 fd:01 1794 /usr/lib64/libdl-2.17.so
7f50f3d71000-7f50f3d72000 rw-p 00003000 fd:01 1794 /usr/lib64/libdl-2.17.so
7f50f3d72000-7f50f3f2a000 r-xp 00000000 fd:01 1788 /usr/lib64/libc-2.17.so
7f50f3f2a000-7f50f4129000 ---p 001b8000 fd:01 1788 /usr/lib64/libc-2.17.so
7f50f4129000-7f50f412d000 r--p 001b7000 fd:01 1788 /usr/lib64/libc-2.17.so
7f50f412d000-7f50f412f000 rw-p 001bb000 fd:01 1788 /usr/lib64/libc-2.17.so
7f50f412f000-7f50f4134000 rw-p 00000000 00:00 0
7f50f4134000-7f50f4154000 r-xp 00000000 fd:01 1780 /usr/lib64/ld-2.17.so
7f50f4237000-7f50f4239000 rw-p 00000000 00:00 0
7f50f424a000-7f50f424b000 rw-p 00000000 00:00 0
7f50f424b000-7f50f424e000 r-xp 00000000 fd:01 1708 /usr/lib64/libonion_security.so.1.0.19
7f50f424e000-7f50f434e000 ---p 00003000 fd:01 1708 /usr/lib64/libonion_security.so.1.0.19
7f50f434e000-7f50f434f000 rw-p 00003000 fd:01 1708 /usr/lib64/libonion_security.so.1.0.19
7f50f434f000-7f50f4353000 rw-p 00000000 00:00 0
7f50f4353000-7f50f4354000 r--p 0001f000 fd:01 1780 /usr/lib64/ld-2.17.so
7f50f4354000-7f50f4355000 rw-p 00020000 fd:01 1780 /usr/lib64/ld-2.17.so
7f50f4355000-7f50f4356000 rw-p 00000000 00:00 0
7ffc4b773000-7ffc4b794000 rw-p 00000000 00:00 0 [stack]
7ffc4b7c4000-7ffc4b7c6000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
select(2004, [Aborted (core dumped)
可见, 在select处core dump了, 所以, 用linux select的时候, 要特别小心, 尤其是在server端, 虽然这种场景不经常发生, 但一旦发生, 就非常难定位。
我个人建议, 在server端, 尽量不要用select, 在client端, 能不用就不用吧!