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上接收到帶外數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章