
linux网络编程系列(十一)--select基本使用以及它和epoll区别
发布日期:2021-05-08 05:59:42
浏览次数:18
分类:精选文章
本文共 2273 字,大约阅读时间需要 7 分钟。
1. 选择函数
在网络编程中,select函数是常用的轮询机制之一,能够监控多个文件描述符的读写状态。本文将简单介绍select函数的使用方法。
1.1 选择函数原型
select函数的原型为:
int select(int maxfdp, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
其中:
- **maxfdp**:表示要监控的文件描述符的最大值加1。 - **readfds**:监控可读的文件描述符集合。返回时,会返回准备就绪的描述符数量。 - **writefds**:监控可写的文件描述符集合。 - **errorfds**:监控文件错误或异常状态的描述符集合。 - **timeout**:超时时间结构体。如果传入NULL,select会进入阻塞状态,直到有描述符发生变化或超时。1.2 选择函数调用
在实际使用中,select函数通常与socket、bind、listen等系统调用配合使用。例如:
struct timeval TimeOut; fd_set readfds, writefds; FD_ZERO(&readfds); FD_SET(socket_fd, &readfds); writefds = readfds; TimeOut.tv_sec = 5; // 设置超时为5秒 pTimeOut = &TimeOut; while (1) { int nRetVal = select(socket_fd + 1, &readfds, &writefds, NULL, pTimeOut); if (nRetVal == 0) { // 超时处理 return 0; } else if ((nRetVal < 0) && (errno == EINTR || errno == EPIPE)) { // 非阻塞模式下可能会出现EINTR或EPIPE,需要重试 continue; } }
1.3 选择函数的使用
在使用select函数之前,需要确保socket设置为非阻塞模式。以下是一个典型的使用示例:
struct timeval TimeOut; fd_set readfds; FD_ZERO(&readfds); FD_SET(socket_fd, &readfds); TimeOut.tv_sec = recv_timeout; // 设置超时时间 while (1) { int nRetVal = select(socket_fd + 1, &readfds, NULL, NULL, &TimeOut); if (nRetVal == 1) { // 有文件描述符准备就绪 int recv_len = recv(socket_fd, recv_buffer, recv_size, 0); if (recv_len == 0) { // 连接已断开 break; } else { // 处理收到的数据 } } else if (nRetVal == 0) { // 超时处理 return 0; } else { // 错误处理 // 例如:errno == EINTR continue; } }
2. 使用选择检测连接已关闭
在网络编程中,连接可能会因为多种原因(如对方端口关闭、网络问题等)而断开。选择函数返回1时,可能有两种情况:1)有数据可读;2)连接已断开。此时需要结合recv函数的返回值来判断具体情况。
例如:
fd_set readfds; struct timeval t_o; FD_ZERO(&readfds); FD_SET(socket_fd, &readfds); t_o.tv_sec = recv_timeout; int ret = select(socket_fd + 1, &readfds, NULL, NULL, &t_o); if (ret == 1) { int recv_len = recv(socket_fd, recv_buffer, recv_size, 0); if (recv_len == 0) { // 连接已断开 return 0; } else { // 处理收到的数据 } }
3. 选择与epoll的区别
选择和epoll都是常用的文件描述符轮询机制,但两者在实现方式和性能上有显著差异:
- **选择**:是轮询式的文件描述符监控,内核会周期性地通知用户空间的变化。虽然效率一般,但对于文件描述符数量较少的情况,选择是足够高效的。 - **epoll**:是基于内核事件驱动模型的,文件描述符一旦注册到内核,内核会自动监控其状态变化,并在发生变化时通过回调机制通知用户空间。这种方式避免了周期性轮询的开销,效率更高。此外,epoll的内核实现使用mmap加速内核和用户空间的信息传递,减少了内存拷贝的开销,这也是epoll比选择更高效的原因之一。
发表评论
最新留言
很好
[***.229.124.182]2025年04月07日 15时20分43秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
使用BAT批处理 匹配查找指定文件夹,并在当文件夹下创建空文件
2019-03-05
wxpython的Hello,World代码探索
2019-03-05
【数字图像处理】OpenCV3 学习笔记
2019-03-05
【单片机开发】智能小车工程(经验总结)
2019-03-05
【单片机开发】基于stm32的掌上游戏机设计 (项目规划)
2019-03-05
KeepAlived介绍、配置示例、KeepAlived配置IPVS、调用脚本进行监控
2019-03-05
【Numpy学习】np.count_nonzero()用法解析
2019-03-05
Scala集合-数组、元组
2019-03-05
Flink Standalone集群安装和部署
2019-03-05
JAVA网络爬虫01-http client爬取网络内容
2019-03-05
04 程序流程控制
2019-03-05
java并发编程(1)
2019-03-05
C++&&STL
2019-03-05
分组背包问题
2019-03-05
子集(LeetCode 78)
2019-03-05
1004 Counting Leaves (30分)
2019-03-05
1093 Count PAT‘s (25分) 含DP做法
2019-03-05
一篇解决JMM与volatile详解(二)
2019-03-05
数据结构之数组与经典面试题(二)
2019-03-05
无锁并发框架-Disruptor的使用(二)
2019-03-05