阻塞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需要提供要監控的陣列,然後由使用者態拷貝到核心態 核心態線性迴圈監控陣列,每次都需要遍歷整個陣列 核心發現檔案描述符狀態符合操作結果,將其返回 所以對於我們監控的...