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

2024-03-25 16:48

本文主要是介绍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

这篇关于C/C++:Linux select 1024 文件描述符限制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/845618

相关文章

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Linux搭建ftp服务器的步骤

《Linux搭建ftp服务器的步骤》本文给大家分享Linux搭建ftp服务器的步骤,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录ftp搭建1:下载vsftpd工具2:下载客户端工具3:进入配置文件目录vsftpd.conf配置文件4:

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

Linux系统管理与进程任务管理方式

《Linux系统管理与进程任务管理方式》本文系统讲解Linux管理核心技能,涵盖引导流程、服务控制(Systemd与GRUB2)、进程管理(前台/后台运行、工具使用)、计划任务(at/cron)及常用... 目录引言一、linux系统引导过程与服务控制1.1 系统引导的五个关键阶段1.2 GRUB2的进化优

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数