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比选择更高效的原因之一。

上一篇:linux网络编程系列(十二)--滑动窗口、拥塞控制、断线重连机制
下一篇:epoll的基本使用

发表评论

最新留言

很好
[***.229.124.182]2025年04月07日 15时20分43秒