选择

选择是进行 I / O 多路复用的另一种方法。其中一个优点是 winsock API 存在。而且,在 Linux 上,select() 修改超时以反映未睡眠的时间量; 大多数其他实现不会这样做。 (POSIX.1 允许任何行为。)

poll 和 select 都有 ppoll 和 pselect 替代方案,允许在等待事件期间处理输入信号。并且它们都变得很慢,有大量的文件描述符(一百个以上),所以选择特定于平台的调用是明智的,例如 Linux 上的 epoll 和 FreeBSD 上的 kqueue。或者切换到异步 API(例如 POSIX aio 或类似 IO 完成端口的东西)。

选择呼叫具有以下原型:

int select(int nfds, fd_set *readfds, fd_set *writefds,
       fd_set *exceptfds, struct timeval *timeout);

fd_set 是文件描述符的位掩码数组,

nfds 是 set + 1 中所有文件描述符的最大数量。

选择的代码片段:

fd_set active_fd_set, read_fd_set;
FD_ZERO (&active_fd_set); // set fd_set to zeros
FD_SET (sock, &active_fd_set); // add sock to the set
// # define FD_SETSIZE sock + 1
while (1) {
    /* Block until input arrives on one or more active sockets. */
    read_fd_set = active_fd_set; // read_fd_set gets overriden each time
    if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0) {
        // handle error
    }
    // Service all file descriptors with input pending.
    for (i = 0; i < FD_SETSIZE; ++i) {
        if (FD_ISSET (i, &read_fd_set)) {
            // there is data for i
    }
}

请注意,在大多数 POSIX 实现中,与磁盘上的文件关联的文件描述符都是阻塞的。所以写入文件,即使这个文件是在 writefds 中设置的,也会阻塞,直到所有字节都不会被转储到磁盘上