linux c學習筆記 select函式詳解

2021-09-01 15:01:13 字數 3163 閱讀 7842

select系統呼叫是用來讓我們的程式監視多個檔案控制代碼(file descriptor)的狀態變化的。程式會停在select這裡等待,直到被監視的檔案控制代碼有某乙個或多個發生了狀態改變。

何為檔案控制代碼????

檔案控制代碼在linux裡很多,如果你man某個函式,在函式返回值部分說到成功後有乙個檔案控制代碼被建立的都是,如man socket可以看到「on success, a file descriptor for the new socket is returned.」而man 2 open可以看到「open() and creat() return the new file descriptor」,其實檔案控制代碼就是乙個整數,看socket函式的宣告就明白了:

int socket(int domain, int type, int protocol);

當然,我們最熟悉的控制代碼是0、1、2三個,0是標準輸入,1是標準輸出,2是標準錯誤輸出。0、1、2是整數表示的,對應的file *結構的表示就是stdin、stdout、stderr,0就是stdin,1就是stdout,2就是stderr。

比如下面這兩段**都是從標準輸入讀入9個位元組字元:

#include

#include

#include

int main(int argc, char ** argv)

/* **上面和下面的**都可以用來從標準輸入讀使用者輸入的9個字元** */

#include

#include

#include

int main(int argc, char ** argv)

繼續上面說的select,就是用來監視某個或某些控制代碼的狀態變化的。select函式原型如下:

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

函式的最後乙個引數timeout顯然是乙個超時時間值,其型別是struct timeval *,即乙個struct timeval結構的變數的指標,所以我們在程式裡要申明乙個struct timeval tv;然後把變數tv的位址&tv傳遞給select函式。struct timeval結構如下:

struct timeval ;

第2、3、4三個引數是一樣的型別: fd_set *,即我們在程式裡要申明幾個fd_set型別的變數,比如rdfds, wtfds, exfds,然後把這個變數的位址&rdfds, &wtfds, &exfds 傳遞給select函式。這三個引數都是乙個控制代碼的集合,第乙個rdfds是用來儲存這樣的控制代碼的:當控制代碼的狀態變成可讀的時系統就會告訴select函式返回,同理第二個wtfds是指有控制代碼狀態變成可寫的時系統就會告訴select函式返回,同理第三個引數exfds是特殊情況,即控制代碼上有特殊情況發生時系統會告訴select函式返回。特殊情況比如對方通過乙個socket控制代碼發來了緊急資料。如果我們程式裡只想檢測某個socket是否有資料可讀,我們可以這樣:

fd_set rdfds; /* 先申明乙個 fd_set 集合來儲存我們要檢測的 socket控制代碼 */

struct timeval tv; /* 申明乙個時間變數來儲存時間 */

int ret; /* 儲存返回值 */

fd_zero(&rdfds); /* 用select函式之前先把集合清零 */

fd_set(socket, &rdfds); /* 把要檢測的控制代碼socket加入到集合裡 */

tv.tv_sec = 1;

tv.tv_usec = 500; /* 設定select等待的最大時間為1秒加500毫秒 */

ret = select(socket + 1, &rdfds, null, null, &tv); /* 檢測我們上面設定到集合rdfds裡的控制代碼是否有可讀資訊 */

if(ret < 0) perror("select");/* 這說明select函式出錯 */

else if(ret == 0) printf("超時\n"); /* 說明在我們設定的時間值1秒加500毫秒的時間內,socket的狀態沒有發生變化 */

else

}

注意select函式的第乙個引數,是所有加入集合的控制代碼值的最大那個值還要加1。比如我們建立了3個控制代碼:

int sa, sb, sc;

sa = socket(...); /* 分別建立3個控制代碼並連線到伺服器上 */

connect(sa,...);

sb = socket(...);

connect(sb,...);

sc = socket(...);

connect(sc,...);

fd_set(sa, &rdfds);/* 分別把3個控制代碼加入讀監視集合裡去 */

fd_set(sb, &rdfds);

fd_set(sc, &rdfds);

在使用select函式之前,一定要找到3個控制代碼中的最大值是哪個,我們一般定義乙個變數來儲存最大值,取得最大socket值如下:

int maxfd = 0;

if(sa > maxfd) maxfd = sa;

if(sb > maxfd) maxfd = sb;

if(sc > maxfd) maxfd = sc;

然後呼叫select函式:

ret = select(maxfd + 1, &rdfds, null, null, &tv); /* 注意是最大值還要加1 */

同樣的道理,如果我們要檢測使用者是否按了鍵盤進行輸入,我們就應該把標準輸入0這個控制代碼放到select裡來檢測,如下:

fd_zero(&rdfds);

fd_set(0, &rdfds);

tv.tv_sec = 1;

tv.tv_usec = 0;

ret = select(1, &rdfds, null, null, &tv); /* 注意是最大值還要加1 */

if(ret < 0) perror("select");/* 出錯 */

else if(ret == 0) printf("超時\n"); /* 在我們設定的時間tv內,使用者沒有按鍵盤 */

else { /* 使用者有按鍵盤,要讀取使用者的輸入 */

scanf("%s", buf);

Linux C 學習筆記

1.linux 程序與訊號 檢視當前系統所有程序的shell命令 ps aux 檢視程序樹 pstree 檢視當前使用者啟動的程序 ps af kill 程序號 kill 9 程序號 強行殺死程序 killall 程序名字 如果乙個程序的父程序被殺死 則init就程式設計當前程序的父程序 了解實時作...

linux c 學習筆記0626

linux下c 網路程式設計,設定接收或者傳送超時,網上很多文章說是用如下 int nnettimeout 1000 1秒,設定傳送超時 setsockopt socket,sol socket,so sndtimeo,char nnettimeout,sizeof int 設定接收超時 setso...

linux C程式設計學習筆記(一)

1.新增檔案 touch 檔名,刪除檔案rm 檔名 2.新增資料夾 mkdir 資料夾名 3.新增並編輯檔案 vi vim 檔名 4.進入 下一層以下的 資料夾 cd 路徑名 5.回到home目錄 cd 6.當前路徑 pwd 7.執行檔案 下一層以下的 路徑 檔名,如果是要執行當前資料夾下的檔案,路...