1、背景知識
我們首先來看看伺服器程式設計的模型,客戶端發來的請求服務端會產生乙個程序來對其進行服務,每當來乙個客戶請求就產生乙個程序來服務,然而程序不可能無限制的產生,因此為了解決大量客戶端訪問的問題,引入了io復用技術。
即:乙個程序可以同時對多個客戶請求進行服務。
也就是說io復用的「介質」是程序(準確的說復用的是select和poll,因為程序也是靠呼叫select和poll來實現的),復用乙個程序(select和poll)來對多個io進行服務,雖然客戶端發來的io是併發的但是io所需的讀寫資料多數情況下是沒有準備好的,因此就可以利用乙個函式(select和poll)來監聽io所需的這些資料的狀態,一旦io有資料可以進行讀寫了,程序就來對這樣的io進行服務。
io多路復用是指核心一旦發現程序指定的乙個或者多個io條件準備讀取,它就通知該程序。io多路復用適用如下場合:
(1)當客戶處理多個描述字時(一般是互動式輸入和網路套介面),必須使用i/o復用。
(2)當乙個客戶同時處理多個套介面時,而這種情況是可能的,但很少出現。
(3)如果乙個tcp伺服器既要處理監聽套介面,又要處理已連線套介面,一般也要用到i/o復用。
(4)如果乙個伺服器即要處理tcp,又要處理udp,一般要使用i/o復用。
(5)如果乙個伺服器要處理多個服務或多個協議,一般要使用i/o復用。
與多程序和多執行緒技術相比,i/o多路復用技術的最大優勢是系統開銷小,系統不必建立程序/執行緒,也不必維護這些程序/執行緒,從而大大減小了系統的開銷。
2、select函式
該函式准許程序指示核心等待多個事件中的任何乙個傳送,並只在有乙個或多個事件發生或經歷一段指定的時間後才喚醒。函式原型如下:
#include
#include
intselect(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout)
返回值:就緒描述符的數目,超時返回0,出錯返回-1
函式引數介紹如下:
(1)第乙個引數maxfdp1指定待測試的描述字個數,它的值是待測試的最大描述字加1(因此把該引數命名為maxfdp1),描述字0、1、2…maxfdp1-1均將被測試。
因為檔案描述符是從0開始的。
(2)中間的三個引數readset、writeset和exceptset指定我們要讓核心測試讀、寫和異常條件的描述字。如果對某乙個的條件不感興趣,就可以把它設為空指標。struct fd_set可以理解為乙個集合,這個集合中存放的是檔案描述符,可通過以下四個巨集進行設定:
void fd_zero(fd_set *fdset); //清空集合
void fd_set(int fd, fd_set *fdset); //將乙個給定的檔案描述符加入集合之中
void fd_clr(int fd, fd_set *fdset); //將乙個給定的檔案描述符從集合中刪除
int fd_isset(int fd, fd_set *fdset); // 檢查集合中指定的檔案描述符是否可以讀寫
(3)timeout告知核心等待所指定描述字中的任何乙個就緒可花多少時間。其timeval結構用於指定這段時間的秒數和微秒數。
struct timeval;
3.**演示(只對客戶端訊息進行讀功能):
select伺服器端:
#include
#include
#include
#include
#include
#include
#include
#include
int startup(char* ip, int port)
int opt = 1;
setsockopt(sock, sol_socket, so_reuseaddr, &opt, sizeof(opt));
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, 10) < 0)
return sock;
}void usage(const
char* proc)
int main(int argc, char* argv)
int listen_sock = startup(argv[1],atoi(argv[2]));
int nums = sizeof(fd_set)*8;
int fds[nums];
int i = 1;
fds[0] = listen_sock;
for( ; i1;
}int max = listen_sock;
fd_set rfds;
while(1)
;for( i=0; iif(fds[i] > -1)}}
switch(select(max+1, &rfds, null, null, &timeout))
if((i==0)&&(fd_isset(fds[i], &rfds)))
//listen_sock
printf("get a client:[%s, %d]\n",inet_ntoa(client.sin_addr), ntohs(client.sin_port));
int j = 0;
for(;jif(fds[j] == -1)}}
else
if((i != 0)&&(fd_isset(fds[i], &rfds)))
else
if(s == 0)
else
}}//for}}
}return
0;}
select伺服器:
用telnet工具測試:
I O多路復用之select
阻塞i o模型 應用程式呼叫乙個i o函式,應用程式會一直等待資料準備好。如果資料沒有準備好,就會一直等待。只有當資料準備好,從核心拷貝到使用者空間io函式才成功返回。非阻塞i o模型 把乙個套介面設定成非阻塞告訴核心,當所有的i o操作無法完成時,不要將程序睡眠,而返回乙個錯誤資訊。此時i o操作...
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需要提供要監控的陣列,然後由使用者態拷貝到核心態 核心態線性迴圈監控陣列,每次都需要遍歷整個陣列 核心發現檔案描述符狀態符合操作結果,將其返回 所以對於我們監控的...