選擇

選擇是進行 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 中設定的,也會阻塞,直到所有位元組都不會被轉儲到磁碟上