linux 伺服器socket的五種模型

2021-06-21 06:07:01 字數 2836 閱讀 4205

一、五種i/o模型

1、阻塞i/o

我們在前面所說的i/o模型都是阻塞i/o,即呼叫recv系統呼叫,如果沒有資料則阻塞等待,當資料到來則將資料從核心空間(套介面緩衝區)拷貝到使用者空間(recv函式提供的buf),然後recv返回,進行資料處理。

2、非阻塞i/o

我們可以使用 fcntl(fd, f_setfl, flag | o_nonblock); 將套接字標誌變成非阻塞,呼叫recv,如果裝置暫時沒有資料可讀就返回-1,同時置errno為ewouldblock(或者eagain,這兩個巨集定義的值相同),表示本來應該阻塞在這裡(would block,虛擬語氣),事實上並沒有阻塞而是直接返回錯誤,呼叫者應該試著再讀一次(again)。這種行為方式稱為輪詢(poll),呼叫者只是查詢一下,而不是阻塞在這裡死等,這樣可以同時監視多個裝置:

while(1) 

如果read(裝置1)是阻塞的,那麼只要裝置1沒有資料到達就會一直阻塞在裝置1的read呼叫上,即使裝置2有資料到達也不能處理,使用非阻塞i/o就可以避免裝置2得不到及時處理。

非阻塞i/o有乙個缺點,如果所有裝置都一直沒有資料到達,呼叫者需要反覆查詢做無用功,如果阻塞在那裡,作業系統可以排程別的程序執行,就不會做無用功了,在實際應用中非阻塞i/o模型比較少用,經常與io multiplexing 一起使用。

3、i/o復用

用select來管理多個i/o,當沒有資料時select阻塞,如果在超時時間內資料到來則select返回,再呼叫recv進行資料的複製,recv返回後處理資料。

4、訊號驅動i/o

先註冊sigio訊號的處理函式,程序繼續執行其他操作,當資料到來時會傳送sigio訊號給程序,然後可以在訊號處理函式中呼叫recv進行資料的複製,然後recv返回進行資料處理。

5、非同步i/o

aio_read 函式也會提供乙個buf,系統呼叫進入核心,如果沒有資料則立即返回,程序繼續執行其他操作,所以叫非同步i/o,當資料到來時核心自動複製資料,然後推送給使用者空間,通過在aio_read中指定的訊號通知程序,讓其處理資料。非同步i/o跟訊號驅動i/o的不同之處在於,它不用呼叫recv進行資料的複製,如果將後者比做」拉pull「,則前者可以認為是」push推「,push的效率會高點,其實非同步i/o跟windows下面的完成埠差不多,但aio_read的實現或多或少存在問題,用得也比較少。

二、select函式簡介

/* according to posix.1-2001 */

#include

/* according to earlier standards */

#include

#include

#include

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

引數1:讀寫異常集合中的檔案描述符的最大值加1;

引數2:讀集合,關心可讀事件;

套介面緩衝區有資料可讀

對等連線的寫一半關閉。即接收到fin段,讀操作將返回0

如果是監聽套介面,已完成連線佇列不為空時。

套介面上發生了乙個錯誤待處理,錯誤可以通過getsockopt指定so_error選項來獲取。

引數3:寫集合,關心可寫事件;

套介面傳送緩衝區有空間容納資料。

對等連線的讀一半關閉。即收到rst段之後,再次呼叫write操作。

套介面上發生了乙個錯誤待處理,錯誤可以通過getsockopt指定so_error選項來獲取。

引數4:異常集合,關心異常事件;

套介面存在帶外資料(tcp頭部 urg標誌,16位緊急指標字段)

引數5:超時時間結構體

對於引數2,3,4來說,如果不關心對應事件則設定為null即可。注意5個引數都是輸入輸出引數,即select返回時可能對其進行了修改,比如集合被修改以便標記哪些套介面發生了事件,時間結構體的傳出引數是剩餘的時間,如果設定為null表示永不超時。用select管理多個i/o,select阻塞等待,一旦其中的乙個或多個i/o檢測到我們所感興趣的事件,select函式返回,返回值為檢測到的事件個數,並且返回哪些i/o傳送了事件,遍歷這些事件,進而處理事件。注意當select阻塞返回後,此時呼叫read/write 是不會阻塞的,因為正是有可讀可寫事件發生才導致select 返回,也可以認為是select 提前阻塞了。

下面是4個可以對集合進行操作的巨集:

void fd_clr(int fd, fd_set *set); // 清除出集合

int  fd_isset(int fd, fd_set *set); // 判斷是否在集合中

void fd_set(int fd, fd_set *set); // 新增進集合中

void fd_zero(fd_set *set); // 將集合清零

select函式的舉例應用看這裡。

伺服器模型 socket

伺服器模型 一 迴圈伺服器 迴圈伺服器在同一時刻只可以相應乙個客戶端請求 二 併發伺服器 併發伺服器在同一時刻可以相應多個客戶端的請求.迴圈伺服器 1.udp伺服器 udp迴圈伺服器的實現非常簡單 udp伺服器每次從套接字上讀取乙個客戶端的請求,處理,然後將結果返回給客戶機.可以用下面的演算法來實現...

Linux伺服器socket埠無法釋放

linux伺服器socket埠無法釋放該如何解決?工作流中一般都有即時訊息伺服器,它佈署在tomcat下,但在tomcat停止時,socket不能釋放,下面我們就一起去看看linux伺服器socket埠無法釋放的解決方法。a 在linux下啟動訊息伺服器時,用 tomcat bin catalina...

python的socket伺服器元件

socketserver 2.x中為socketserver class baserequesthandler def init self,request,client address,server self.request request self.client address client ad...