I O多路復用之select

2021-08-03 10:27:04 字數 4355 閱讀 3818

阻塞i/o模型

應用程式呼叫乙個i/o函式,應用程式會一直等待資料準備好。如果資料沒有準備好,就會一直等待。只有當資料準備好,從核心拷貝到使用者空間io函式才成功返回。

非阻塞i/o模型

把乙個套介面設定成非阻塞告訴核心,當所有的i/o操作無法完成時,不要將程序睡眠,而返回乙個錯誤資訊。此時i/o操作函式將不斷的測試資料是否準備好,如果沒有準備好,繼續測試,知道資料準備好為止。不斷測試的過程中會占用cpu時間。

i/o復用模型

i/o復用模型會用到select或者poll函式,這兩個函式會使程序阻塞,並同時阻塞多個i/o操作,而且同時對多個讀寫操作的i/o函式進行檢測,知道有資料刻毒或可寫,才正真i/o操作函式。

訊號驅動i/o模型

允許套接字進行訊號驅動i/o,並安裝訊號驅動函式,程序繼續執行並不停止,當資料=準備好時,程序會收到sigio訊號,可以在訊號處理函式中呼叫i/o操作函式進行處理數。

非同步i/o模型

呼叫aio_read函式,告訴核心描述字,緩衝區指標,緩衝區大小,檔案偏移以及通知方式,然後立即返回。當核心資料拷貝到緩衝區後,再通知應用程式

大部分場景,乙個程式或網路服務出現效能問題時,可以優先考慮i/o所帶來的影響。

站在使用者的角度,i/o分兩個階段完成,第一階段是等事件就緒,第二階段才是真正的進行i/o操作。

對於這5種i/o模型,前四種第一二階段基本相同,都是等資料就緒後將其從核心拷貝到呼叫者的緩衝區。而非同步i/o模型不同。

影響i/o效能主要是第一階段等待資料就緒的時候。

提高i/o效能,首先要考慮i/o等的比重。

主要講述下i/o復用模型及select

i/o多路復用指核心一旦發現程序指定的乙個或多個io條件準備讀取,它就通知程序。

i/o復用一般用於一下場合:

客戶端程式要同時處理多個socket。

客戶端程式要同時處理使用者輸入和網路連線

tcp伺服器要同時處理監聽socket和連線socket。這時i/o復用使用最多的場合

伺服器要同時處理tcp和udp請求。

伺服器要同時監聽多個埠或者處理多種服務。

i/o復用雖然能同時監聽多個檔案描述符,但它本身是阻塞的。並且當多個檔案描述符同時就緒的同時,如果不採取額外的措施,程式就只能按照順序的依次處理其中的每乙個檔案描述符,這就使得伺服器程式看起來是序列工作的。當然如果要實現併發,只能使用多執行緒或多程序程式設計。

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);

struct timeval ;

//第乙個引數nfds指定要堅挺的檔案描述符的總數,測試的範圍是在0到nfds-1的檔案描述(nfds為這些檔案描述符的最大值+1,因為檔案描述符是從0開始的)。

//後面4個引數是輸入輸出型引數,第2、3、4引數型別都是fd_set*(檔案描述符集)。readfds、writefds、exceptfds分別指向可讀、可寫、可寫的檔案描述符集。當select呼叫返回時,核心將修改它們通知應用程式那個檔案描述符就緒。

//最後乙個引數timeout用來設定select呼叫的超時時間。採用timeval結構型別的指標,核心將修改它來告訴應用程式select等待了多久。

//select成功返回就緒的檔案描述符的總數;返回0時,說明還沒有檔案描述符就緒。失敗返回-1並設定errno

select操作函式

void fd_clr(int fd, fd_set *set);//用來清除set中fd相關的位

int fd_isset(int fd, fd_set *set);//用來檢測set中fd相關的位是否為真

void fd_set(int fd, fd_set *set);//用來設定set中fd相關的位

void fd_zero(fd_set *set);//用來清除set中的所有`

include#include

#include

#include

#include

#include

#include

#include

#include

#include

int fds[1024];

static

void usage(const

char* proc)

int startup(const

char* ip,int port)

struct sockaddr_in local;

local.sin_family=af_inet;

local.sin_port=htons(port);

local.sin_addr.s_addr=inet_addr(ip);

if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)//繫結位址資訊

if(listen(sock,5)<0)//伺服器監聽網路

return sock;

}int main(int argc,char* argv)

int listen_sock=startup(argv[1],atoi(argv[2]));//監聽套接字

int nums=sizeof(fds)/sizeof(fds[0]);

int maxfd=-1;

int i=1;

for(i=1;i1;//將放檔案描述符的陣列初始化位-1

}fds[0]=listen_sock;//用陣列的第乙個放listen_sock

while(1)

;fd_set rfds;//定義檔案描述符集

fd_zero(&rfds);//每次進來將清除rfds的全部位

maxfd=-1;

for(i=0;i//遍歷fds陣列,看哪個檔案描述符有效}}

switch(select(maxfd+1,&rfds,null,null,&timeout))

if(i==0 && fd_isset//listen_sock(listen_sock,&rfds))

printf("get a new client[%s,%d]\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));

int j=1;

for(j=1;j//將新的識別符號檔案描述符放入fds中

}if(j==nums)

else

}//if

else

if((i>0)&&fd_isset(fds[i],&rfds))//第二次輪詢的時候fds[i]=new_fd ready,進行讀事件

else

if(s==0)

else

}}//else if

else

{}}//for

}//default

break;

}//switch

}//while

return

0;}

#include

#include

#include

#include

#include

#include

#include

void usage(const

char* proc)

int main(int argc,char* argv)

int sock=socket(af_inet,sock_stream,0);

if(sock<0)

struct sockaddr_in remote;

remote.sin_family=af_inet;

remote.sin_port=htons(atoi(argv[2]));

remote.sin_addr.s_addr=inet_addr(argv[1]);

if(connect(sock,(struct sockaddr*)&remote,sizeof(remote))<0)

char buf[1024];

while(1)

}return

0;}

select缺點

IO多路復用之select

1 背景知識 我們首先來看看伺服器程式設計的模型,客戶端發來的請求服務端會產生乙個程序來對其進行服務,每當來乙個客戶請求就產生乙個程序來服務,然而程序不可能無限制的產生,因此為了解決大量客戶端訪問的問題,引入了io復用技術。即 乙個程序可以同時對多個客戶請求進行服務。也就是說io復用的 介質 是程序...

I O多路復用之select

select是用於監視多個檔案描述符狀態的變化的。即用來監視檔案描述符讀 寫 異常狀態是否就緒。函式原型 int select int nfds,fd set readfds,fd set writefds,fd set exceptfds,struct timeval timeout select...

IO多路復用之select

原理 i o多路復用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒,能夠通知程式進行相應的操作。select執行流程 select需要提供要監控的陣列,然後由使用者態拷貝到核心態 核心態線性迴圈監控陣列,每次都需要遍歷整個陣列 核心發現檔案描述符狀態符合操作結果,將其返回 所以對於我們監控的...