標籤:i/o複用
I/O複用使得程式能同時監聽多個檔案描述符,對提高程式的效能至關重要。
I/O複用雖然能同時監聽多個檔案描述符,但它本身是阻塞的。當多個檔案描述符同時就緒時,如果不採取額外的措施,程式就只能按順序依次處理其中的每一個檔案描述符,伺服器程式看起來像是串列工作的。如果要實現並發,只能使用多進程或多線程等編程手段。
linux下實現I/O複用的系統調用主要有select、poll、epoll。
select系統調用
select系統調用的用途是:在一段指定時間內,監聽使用者感興趣的檔案描述符上的可讀、可寫和異常等事件。
#include <sys/select.h>
int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);
1、nfds參數指定被監聽的檔案描述符的總數。通常被設定為select監聽的所有檔案描述符中的最大值加1,因為檔案描述符是從0開始計數的。
2、readfds、writefds和exceptfds參數分別指向可讀、可寫和異常等事件對應的檔案描述符集合。
fd_set結構體僅包含一個整形數組,該數組的每個元素的每一位(bit)標記一個檔案描述符。fd_set能容納的檔案描述符數量有FD_SETSIZE指定,這就限制了select能同時處理的檔案描述符的數量。
由於位操作過於煩瑣,使用下面的一系列宏來訪問fd_set結構體中的位:
#include <sys/select.h>
FD_ZERO(fd_set *fdset); //清除fdset的所有位
FD_SET(int fd, fd_set *fdset); //設定fdset的位fd
FD_CLR(int fd, fd_set *fdset); //清除fdset的位fd
int FD_ISSET(int fd, fd_set *fdset); //測試fdset的位fd是否被設定
3、timeout參數用來設定select函數的逾時時間。
select成功時返回就緒(可讀、可寫和異常)檔案描述符的總數。如果在逾時時間內沒有任何檔案描述符就緒,select返回0。select失敗時返回-1並設定error。如果在select等待期間,程式接收到訊號,則select立即返回-1,並設定error為EINTR。
檔案描述符就緒條件
下列情況下socket可讀:
1、socket核心接收緩衝區中的位元組數大於或等於其低水位標記SO_RCVLOWAT。此時可以無阻塞地讀該socket,並且讀操作返回的位元組數大於0。
2、socket通訊的對方關閉串連。此時對該socket的讀操作將返回0。
3、監聽socket上有新的串連請求。
4、socket上有未處理的錯誤。此時可以使用getsockopt來讀取和清除該錯誤。
下列情況下socket可寫:
1、socket核心發送緩衝區中的可用位元組數大於或等於其低水位標記SO_SNDLOWAT。此時可以無阻塞地寫該socket,並且寫操作返回的位元組數大於0。
2、socket的寫操作被關閉。對寫操作被關閉的socket執行寫操作將觸發一個SIGPIPE訊號。
3、socket使用非阻塞connect串連成功或失敗(逾時)之後。
4、socket上有未處理的錯誤。此時可以使用getsockopt來讀取和清除該錯誤。
網路程式中,select能處理的異常情況只有一種:socket上接收到帶外資料。