您的位置:首页 > 房产 > 建筑 > 网站建立的步骤是_现在深圳疫情最新消息_市场营销推广方案_北京seo优化厂家

网站建立的步骤是_现在深圳疫情最新消息_市场营销推广方案_北京seo优化厂家

2025/5/13 9:24:25 来源:https://blog.csdn.net/niuTyler/article/details/147089958  浏览:    关键词:网站建立的步骤是_现在深圳疫情最新消息_市场营销推广方案_北京seo优化厂家
网站建立的步骤是_现在深圳疫情最新消息_市场营销推广方案_北京seo优化厂家

文件描述符集合(fd_set)详解

文件描述符集合(fd_set)是 Unix/Linux 系统中用于 I/O 多路复用(如 selectpollepoll)的重要数据结构。它允许程序同时监控多个文件描述符(如套接字、管道、文件等),并在它们可读、可写或发生异常时高效地处理 I/O 操作。

本文将详细介绍:

  1. 文件描述符集合的基本概念
  2. fd_set 的结构与实现
  3. 核心操作宏(FD_ZERO、FD_SET、FD_CLR、FD_ISSET)
  4. select 系统调用如何使用 fd_set
  5. 文件描述符集合的优缺点
  6. 现代替代方案(pollepoll

1. 文件描述符集合(fd_set)是什么?

在 Unix/Linux 系统中,每个打开的文件、套接字、管道等都会分配一个 文件描述符(File Descriptor, fd),它是一个非负整数(如 0 是标准输入,1 是标准输出,2 是标准错误)。

文件描述符集合(fd_set 是一种数据结构,用于存储一组文件描述符,以便系统调用(如 select)可以同时监控它们的 I/O 状态(可读、可写、异常)。


2. fd_set 的结构与实现

fd_set 通常是一个 位图(bitmap),即一个固定大小的数组,其中每一位(bit)代表一个文件描述符的状态:

  • 1(置位):表示该文件描述符在集合中,需要被监控。
  • 0(清零):表示该文件描述符不在集合中,不监控。

fd_set 的典型定义

#include <sys/select.h>typedef struct {unsigned long fds_bits[FD_SETSIZE / (8 * sizeof(unsigned long))];
} fd_set;
  • FD_SETSIZE 是一个宏,通常定义为 1024,表示 fd_set 最多可以监控 0~1023 号文件描述符。
  • fds_bits 是一个 unsigned long 数组,每个 unsigned long 通常占 8 字节(64 位),因此可以存储 64 个文件描述符的状态。

3. 核心操作宏

fd_set 不能直接操作,而是通过以下宏进行管理:

作用示例
FD_ZERO(fd_set *set)清空集合(所有位设为 0)FD_ZERO(&read_fds);
FD_SET(int fd, fd_set *set)fd 加入集合(对应位置 1)FD_SET(sockfd, &read_fds);
FD_CLR(int fd, fd_set *set)从集合中移除 fd(对应位置 0)FD_CLR(sockfd, &read_fds);
FD_ISSET(int fd, fd_set *set)检查 fd 是否在集合中(返回 1 表示存在)if (FD_ISSET(sockfd, &read_fds)) {...}

4. select 如何使用 fd_set

select 是最早的 I/O 多路复用机制,它使用 fd_set 来监控多个文件描述符的状态。

select 函数原型

#include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • nfds:最大的文件描述符 +1(select 会检查 0nfds-1 的 fd)。
  • readfds:监控可读的文件描述符集合。
  • writefds:监控可写的文件描述符集合。
  • exceptfds:监控异常的文件描述符集合。
  • timeout:超时时间(NULL 表示阻塞,0 表示非阻塞)。

select 的工作流程

  1. 初始化 fd_set
    fd_set read_fds;
    FD_ZERO(&read_fds);  // 清空集合
    FD_SET(sockfd1, &read_fds);  // 添加 sockfd1
    FD_SET(sockfd2, &read_fds);  // 添加 sockfd2
    
  2. 调用 select
    int max_fd = (sockfd1 > sockfd2) ? sockfd1 : sockfd2;
    int ready = select(max_fd + 1, &read_fds, NULL, NULL, NULL);
    
  3. 检查哪些 fd 就绪
    if (FD_ISSET(sockfd1, &read_fds)) {// sockfd1 可读
    }
    if (FD_ISSET(sockfd2, &read_fds)) {// sockfd2 可读
    }
    

5. 文件描述符集合的优缺点

优点

跨平台:几乎所有 Unix/Linux 系统都支持 select
简单易用:适合少量文件描述符的监控。

缺点

性能问题

  • select 每次调用都要遍历所有 fd,时间复杂度 O(n)
  • fd_set 大小受限(默认 1024)。
    每次调用都要重新设置 fd_set(因为 select 会修改传入的集合)。
    不支持事件驱动,必须轮询检查。

6. 现代替代方案(pollepoll

由于 select 的局限性,现代程序更倾向于使用 pollepoll

机制特点
poll使用 struct pollfd 数组,没有 fd_set 的大小限制。
epollLinux 特有,高性能事件驱动模型,适用于高并发场景(如 Nginx)。

poll 示例

struct pollfd fds[2];
fds[0].fd = sockfd1; fds[0].events = POLLIN;
fds[1].fd = sockfd2; fds[1].events = POLLIN;int ready = poll(fds, 2, -1);  // 阻塞等待
if (fds[0].revents & POLLIN) { /* sockfd1 可读 */ }

epoll 示例

int epfd = epoll_create1(0);
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = sockfd1;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd1, &ev);struct epoll_event events[10];
int n = epoll_wait(epfd, events, 10, -1);
for (int i = 0; i < n; i++) {if (events[i].data.fd == sockfd1) { /* 处理 sockfd1 */ }
}

总结

  • fd_setselect 使用的位图结构,用于监控多个文件描述符的 I/O 状态
  • select 适用于少量连接,但性能较差,现代程序更推荐 pollepoll
  • epoll 是 Linux 高性能 I/O 多路复用的最佳选择,适用于高并发服务器(如 Web 服务器、数据库)。

希望本文能帮助你深入理解文件描述符集合及其应用!🚀

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com