Socket超時設定 select 的妙用

2021-05-23 06:59:23 字數 2181 閱讀 3111

===========================================

阻塞與非阻塞

在 server 進入 listen 狀態之後, 我們下面分別討論兩種實現方法:

1. fcntl 方法

對乙個檔案描述符指定的檔案或裝置, 有兩種工作方式: 阻塞與非阻塞, 阻塞的意思是指, 當試圖對該檔案描述符進行讀寫時, 如果當時沒有東西可讀, 或者暫時不可寫, 程式就進入等待狀態, 直到有東西可讀或者可寫為止. 而對於非阻塞狀態, 如果沒有東西可讀, 或者不可寫, 讀寫函式馬上返回, 而不會等待. 預設情況下, 檔案描述符處於阻塞狀態. 在實現聊天室時, server 輪流查詢與各client 建立 socket, 一旦可讀就將該 socket 中的字元讀出來並向所有其他client 傳送. 並且, server 還要隨時檢視是否有新的 client 試圖建立連線, 這樣, 如果 server 在任何乙個地方阻塞了, 其他 client 傳送的內容就會受到影響, 新 client 試圖建立連線也會受到影響. 因此, 我們使用 fcntl 將該

檔案描述符變為非阻塞的:

fcntl( sockfd, f_setfl, o_nonblock);

// sockfd      是要改變狀態的檔案描述符.

// f_setfl     表明要改變檔案描述符的狀態

// o_nonblock  表示將檔案描述符變為非阻塞的.

使用自然語言描述聊天室 server :

while ( 1)}}

}由於判斷是否有新連線, 是否可讀都是非阻塞的, 因此每次判斷, 不管有還是沒有, 都會馬上返回. 這樣, 任何乙個 client 向 server 傳送字元或者試圖建立新連線, 都不會對其他 client 的活動造成影響. 對 client 而言, 建立連線之後, 只需要處理兩個檔案描述符, 乙個是建立了連線的 socket 描述符, 另乙個是標準輸入. 和 server 一樣, 如果使用阻塞方式的話, 很容易因為其中乙個暫時沒有輸入而影響另外乙個的讀入. 因此將它們都變成非阻塞的, 然後client 進行如下動作:

while( 不想退出)

if ( 標準輸入可讀)

}分析上面的程式可以知道, 不管是 server 還是 client, 它們都不停的輪流查詢各個檔案描述符, 一旦可讀就讀入並進行處理. 這樣的程式, 不停的在執行, 只要有cpu 資源, 就不會放過. 因此對系統資源的消耗非常大. server 或者 client 單獨執行時, cpu 資源的 98% 左右都被其占用. 因此, 我們可以使用另外一種阻塞的方法來解決這個問題, 這就是 select.

2. select 方法

select 方法中, 所有檔案描述符都是阻塞的. 使用 select 判斷一 組檔案描述符中是否有乙個可讀(寫), 如果沒有就阻塞, 直到有乙個的時候就被喚醒. 我們先看比較簡單的 client 的實現:

由於 client 只需要處理兩個檔案描述符, 因此, 需要判斷是否有可讀寫的檔案描述符只需要加入兩項:

fd_zero( sockset);          // 將 sockset 清空

fd_set( sockfd, sockset);   // 把 sockfd 加入到 sockset 集合中

fd_set( 0, sockset);        // 把 0 (標準輸入) 加入到 sockset 集合中

然後 client 的處理如下:

while ( 不想退出)

if ( fd_isset( 0, &sockset))

重新設定 sockset. (即將 sockset 清空, 並將 sockfd 和 0 加入)

}下面看 server 的情況:

設定 sockset 如下:

fd_zero( sockset);

fd_set( sockfd, sockset);

for ( 所有有效連線)

maxfd = 最大的檔案描述符號 + 1;

server 處理如下:

while ( 1)

for( 所有有效連線)

}重新設定 sockset;

}由於採用 select 機制, 因此當沒有字元可讀時, 程式處於阻塞狀態, 最小程度的占用cpu 資源, 在同一臺機器上執行乙個 server 和若干個client 時, 系統負載只有 0.1 左右, 而採用原來的 fcntl 方法, 只執行乙個 server, 系統負載就可以達到 1.5 左右. 因此我們推薦使用 select.

socket 超時設定

在send recv 過程中有時由於網路狀況等原因,收發不能預期進行,而設定收發超時控制 這樣做在linux環境下是不會產生效果的,須如下定義 struct timeval timeout 設定傳送超時 setsockopt socket,sol socket,so sndtimeo,char ti...

socket超時設定

在使用socket程式設計時,肯定會遇到設定超時的問題。有些人可能會認為socket類的setsotimeout sotimeout 方法就是設定超時。其實不然,socket設定超時分為兩種,上面提到為讀寫超時。第一 建立連線的超時設定,如下 socket.connect socketaddress...

socket 設定阻塞超時

connect 設定超時 核心connect超時通常為75秒,我們可以設定更小的時間如10秒來提前從connect中返回 這裡用使用訊號處理機制,呼叫alarm,超時後產生sigalrm訊號 也可使用select實現 sigfunc sigfunc sigfunc signal sigalrm,co...