select函數

select函數

select()函數容許進程指示內核等待多個事件中的任何一個發生,並只在有一個或多個事件發生
或經歷一段指定時間後才喚醒它
#include <sys/select.h>
#include <sys/time.h>
// 返回值:如有就緒描述符,則返回就緒描述符數目;若超時則返回0,出錯返回-1 int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);

select的參數:

maxfdp1:
指定待測試的描述符個數,它的值是待測試的最大描述符加1
 
readset、writeset、exceptset:
指定讓內核測試讀、寫、異常條件的描述符

異常條件:
某個套接字的帶外數據到達
某個已置爲分組模式的僞終端存在能夠從其主端讀取的控制狀態信息
 
fd_set *: select使用的描述符集
系統提供了4個宏對描述符集進行操做:
#include <sys/select.h>
#include <sys/time.h>
void FD_SET(int fd, fd_set *fdset);   // 設置文件描述符集fdset中對應於文件描述符fd的位(設置爲1)
void FD_CLR(int fd, fd_set *fdset);   // 清除文件描述符集fdset中對應於文件描述符fd的位(設置爲0)
void FD_ISSET(int fd, fd_set *fdset); // 檢測文件描述符集fdset中對應於文件描述符fd的位是否被設置
void FD_ZERO(fd_set *fdset);          // 清除文件描述符集fdset中的全部位(既把全部位都設置爲0

注意:服務器

在使用FD_ISSET測試fd_set數據類型中的描述符後,描述符集內任何與未就緒描述符對應函數

的位返回時均被清0,所以,每次從新調用select函數時,都須要將描述符集內所關心的位置爲1測試

描述符必須被初始化,由於做爲自動變量分配的一個描述符若是沒有被初始化,那麼發生的後果
不可預期
 
readset、writeset、exceptset三個參數中,若對其中任何參數條件不感興趣,則可將其設爲 NULL
timeout:
告知內核等待指定描述符中的任何一個就緒的時間限制
timeval結構:
struct timeval{
    long tv_sec;    //
    long tv_usec;   // 微秒
}

 

timeout參數的三種可能:
a.設爲空指針:永遠等待下去,僅在有描述符就緒時才返回
b.正常設置timeout,在不超過timeout設置的時間內,在有描述符就緒時返回
c.將timeout.tv_sec和timeout.tv_usec都設爲0:檢查描述符後當即返回(輪詢) 

a b 兩種情形的等待一般會被進程在 等待期間捕獲的信號中斷,並 從信號處理函數返回,所以在
考慮可移植性的狀況下,若咱們在捕獲信號,那必須作好 select返回EINTR錯誤的準備
 
描述符的就緒條件:
可讀條件:
1.該套接字接收緩衝區中的數據字節數大於等於套接字接收緩衝區低水位標記的當前大小
2.該鏈接的讀半部關閉(即接收了FIN的TCP鏈接)
3.該套接字是一個監聽套接字且已完成的鏈接數不爲0
4.該套接字上有一個套接字錯誤待處理
 
可寫條件:
1.該套接字發送緩衝區中的可用空間字節數大於等於套接字發送緩衝區低水位標記的當前大小
2.該鏈接的寫半部關閉
3.使用非阻塞式connect的套接字已創建鏈接,或者connect已經以失敗了結
4.該套接字上有一個套接字錯誤待處理
 
異常條件:
a.該套接字存在帶外數據或者仍處於帶外標記
 
接受緩衝區低水位標記(讀):讓select返回套接字接收緩衝區所需數據量
發送緩衝區低水位標記(寫):讓select返回套接字發送緩衝區可用空間
 
示例:
 91 // 使用select的cli_io函數,使得在服務器進程終止後客戶能夠立刻獲取通知
 92 void cli_io_select(int sockfd, char *mark, FILE *fp)
 93 {
 94     int maxfdp1, n;
 95     fd_set rset;
 96     char sendline[MAXLINE], recvline[MAXLINE];
 97 
 98     FD_ZERO(&rset);
 99 
100     for ( ; ; )
101     {
102         FD_SET(fileno(fp), &rset);
103         FD_SET(sockfd, &rset);
104 
105         // fileno() 函數,將文件流指針轉換爲文件描述符·
106         maxfdp1 = max(fileno(fp), sockfd) + 1;
107 
108         if (select(maxfdp1, &rset, NULL, NULL, NULL) < 0)
109         {
110             printf("Error select!\n");
111             exit(1);
112         }
113 
114         if (FD_ISSET(sockfd, &rset))
115         {
116             if ( (n = read(sockfd, recvline, MAXLINE)) > 0 )
117             {
118                 recvline[n] = '\0';
119                 fputs(recvline, stdout);
120             }
121         }
122 
123         if (FD_ISSET(fileno(fp), &rset))
124         {
125             if (fgets(sendline, MAXLINE, fp) == NULL)
126             {
127                 return;
128             }
129 
130             if (write(sockfd, sendline, strlen(sendline)) < 0)
131             {
132                 printf("Error write!\n");
133                 exit(1);
134             }
135         }
136     }
137 }
相關文章
相關標籤/搜索