C/C++:Linux select 1024 文件描述符限制

C/C++:Linux select 1024 文件描述符限制

通常來說,Linux下select調用要求文件描述符的值小於1024,也就是說,fd set中的每個文件描述符的值域爲:[0,1023]。

如果超過,Linux下select調用會發生什麼?

環境:

[test1280@localhost ~]$ uname -a
Linux localhost.localdomain 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

方法:

通過dup2生成指定數值的文件描述符,並將其與標準輸入關聯,select的讀集合包含且只包含指定數值文件描述符。

代碼:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>

int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		fprintf(stderr, "usage: %s fd\n", argv[0]);
		exit(1);
	}

	int fd = atoi(argv[1]);
	if (fd < 3) // <0 0 1 2
	{
		fprintf(stderr, "fd domain: (2, fd_max]\n");
		exit(1);
	}

	fprintf(stdout, "fd size: %d\n", FD_SETSIZE);

	// 創建指定文件描述符,與標準輸入關聯
	if (dup2(0, fd) == fd)
	{
		fprintf(stdout, "dup2 ok! new fd: %d\n", fd);
	}
	else
	{
		fprintf(stderr, "dup2 error: %d(%s)\n", errno, strerror(errno));
		exit(1);
	}

	// 設爲非阻塞
	long flags = fcntl(fd, F_GETFL);	
	fcntl(fd, F_SETFL, flags|O_NONBLOCK);

	fprintf(stdout, "will into main loop...\n");

	while (1)
	{
		fd_set readSet;
		FD_ZERO(&readSet);
		FD_SET(fd, &readSet);

		struct timeval tv;
		tv.tv_sec = 3;
		tv.tv_usec = 0;

		int res = select(fd + 1, &readSet, NULL, NULL, &tv);
		if (res == -1) {
			fprintf(stderr, "select error: %d(%s)\n", errno, strerror(errno));
			exit(1);
		} else if (res == 0) {
			fprintf(stdout, "timeout...\n");
		} else {
			static char buff[1024];
			int count = read(fd, buff, sizeof(buff));
			fprintf(stdout, "select return %d, read count %d\n", res, count);
		}
	}

	exit(0);
}

編譯:

[test1280@localhost ~]$ gcc -o main main.c -g -Wall

運行:

case 1(正常態):

[test1280@localhost ~]$ ./main 10
fd size: 1024
dup2 ok! new fd: 10
will into main loop...
timeout...
timeout...
test1280timeout...

select return 1, read count 9
timeout...
^C

case 2(異常態):

[test1280@localhost ~]$ ./main 1280
fd size: 1024
dup2 ok! new fd: 1280
will into main loop...
select error: 9(Bad file descriptor)

可讀、可寫、異常文件描述符集合包含大於1024的文件描述符時,執行select將返回EBADF錯誤。

但是,並不總是這樣的!

在另一個程序中,將一個大於1024的FD加入到select可讀監聽集合執行select時,發生:

此FD沒有輸入數據,不可讀,select並沒有等待指定的時間返回0,而是立刻返回一個正數指代存在可讀FD。

我沒有能在以上的代碼中復現這個問題。(以上代碼執行select發現非法FD,直接返回EBADF錯誤)

在網絡上別人的博客中,曾出現過段錯誤的異常:

https://my.oschina.net/u/1780368/blog/491863

man 2 select:

POSIX allows an implementation to define an upper limit, advertised
via the constant FD_SETSIZE, on the range of file descriptors that
can be specified in a file descriptor set. The Linux kernel imposes
no fixed limit, but the glibc implementation makes fd_set a fixed-
size type, with FD_SETSIZE defined as 1024, and the FD_*() macros
operating according to that limit. To monitor file descriptors
greater than 1023, use poll(2) instead.
According to POSIX, select() should check all specified file
descriptors in the three file descriptor sets, up to the limit
nfds-1. However, the current implementation ignores any file
descriptor in these sets that is greater than the maximum file
descriptor number that the process currently has open. According to
POSIX, any such file descriptor that is specified in one of the sets
should result in the error EBADF.

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.

Although there are some ways to increase this limit (because of you’re using Linux, everything is possible), select() call can only listen 1024 file descriptor at the same time and all of the file descriptor number must be less than 1024.

總結:

1.select要求三個入參被監聽集合的FD(取值)不超過1024;由此可推2、4:

2.select要求三個入參被監聽集合的FD(數量)不超過1024;

3.若超過1024,執行select可能發生段錯誤,可能發生立刻返回不阻塞(以及錯誤的返回值結果),等等。

4.即使select監聽集合中只有一個FD,如果FD值大於1024,同樣有問題。

參考:

1.https://linux-tips.com/t/is-it-possible-to-listen-file-descriptor-greater-than-1024-with-select/45
2.https://my.oschina.net/u/1780368/blog/491863
3.http://man7.org/linux/man-pages/man2/select.2.html
4.http://bbs.chinaunix.net/thread-1791112-1-1.html
5.https://blog.codingnow.com/2014/02/select_bug.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章