一、select函數簡介
select一般用在socket網絡編程中,在網絡編程的過程中,經常會遇到許多阻塞的函數,網絡編程時使用的recv, recvfrom、connect函數都是阻塞的函數,當函數不能成功執行的時候,程序就會一直阻塞在這里,無法執行下面的代碼。這是就需要用到非阻塞的編程方式,使用 selcet函數就可以實現非阻塞編程。
selcet函數是一個輪循函數,即當循環詢問文件節點,可設置超時時間,超時時間到了就跳過代碼繼續往下執行
select(),確定一個或多個套接口的狀態,本函數用於確定一個或多個套接口的狀態,對每一個套接口,調用者可查詢它的可讀性、可寫性及錯誤狀態信息,用fd_set結構來表示一組等待檢查的套接口,在調用返回時,這個結構存有滿足一定條件的套接口組的子集,並且select()返回滿足條件的套接口的數目。
通常采用select實現多路復用,也就是說可以同時監聽多個文件描述符;
下面是select的函數原型:
1 /* According to POSIX.1-2001 */ 2 #include <sys/select.h> 3 4 int select(int nfds, fd_set *readfds, fd_set *writefds, 5 fd_set *exceptfds, struct timeval *timeout);
下面進行具體的解釋:
第一個參數:int nfds--->是一個整數值,是指集合中所有文件描述符的范圍,即所有文件描述符的最大值加1
第二個參數:fd_set *readfds---->用來檢查一組可讀性的文件描述符。
第三個參數:fd_set *writefds---->用來檢查一組可寫性的文件描述符。
第四個參數:fd_set *exceptfds---->用來檢查文件文件描述符是否異常
第五個參數:sreuct timeval *timeout--->是一個時間結構體,用來設置超時時間
timeout:最多等待時間,對阻塞操作則為NULL
select函數的返回值
負值:select錯誤
正值:表示某些文件可讀或可寫
0:等待超時,沒有可讀寫或錯誤的文件
下面是一些跟select一起使用的函數及結構的作用
1 void FD_ZERO(fd_set *set);//清空一個文件描述符的集合 2 void FD_SET(int fd, fd_set *set);//將一個文件描述符添加到一個指定的文件描述符集合中 3 void FD_CLR(int fd, fd_set *set);//將一個指定的文件描述符從集合中清除; 4 int FD_ISSET(int fd, fd_set *set);//檢查集合中指定的文件描述符是否可以讀寫
struct timeval結構是用來設置超時時間的,該結構體可以精確到秒跟毫秒
1 struct timeval { 2 time_t tv_sec; /* seconds */ 3 suseconds_t tv_usec; /* microseconds */ 4 };
下面是select常用的一個例子:
#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int main(int argc, cahr **argv) { struct timeval timeout; int ret = 0; fd_set rfds; FD_ZERO(&rfds);//清空描述符集合 FD_SET(0, &rfds);//將標准輸入(stdin)添加到集合中 FD_SET(sockfd, &rfds);//將我們的套接字描述符添加到集合中 /*設置超時時間*/ timeout.tv_sec = 1; timeout.tv_usec = 0; /*監聽套接字是否為可讀*/ ret = select(sockfd+1, &rfds, NULL, NULL, &timeout); if(ret == -1) {//select 連接失敗 perror("select failure\n"); return 1; } else if(ret == 0) {//超時(timeout) return 1; } if(FD_ISSET(pesockfd, &rfds)) {//如果可讀 //recv or recvfrom .................. } return 0; }
