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