IO多路復用之select總結

2021-06-21 04:09:38 字數 4030 閱讀 4678

1、基本概念

io多路復用是指核心一旦發現程序指定的乙個或者多個io條件準備讀取,它就通知該程序。io多路復用適用如下場合:

(1)當客戶處理多個描述字時(一般是互動式輸入和網路套介面),必須使用i/o復用。

(2)當乙個客戶同時處理多個套介面時,而這種情況是可能的,但很少出現。

(3)如果乙個tcp伺服器既要處理監聽套介面,又要處理已連線套介面,一般也要用到i/o復用。

(4)如果乙個伺服器即要處理tcp,又要處理udp,一般要使用i/o復用。

(5)如果乙個伺服器要處理多個服務或多個協議,一般要使用i/o復用。

與多程序和多執行緒技術相比,i/o多路復用技術的最大優勢是系統開銷小,系統不必建立程序/執行緒,也不必維護這些程序/執行緒,從而大大減小了系統的開銷。

2、select函式

該函式准許程序指示核心等待多個事件中的任何乙個傳送,並只在有乙個或多個事件發生或經歷一段指定的時間後才喚醒。函式原型如下:

#include select.h>#include 

time.h>

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均將被測試。

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

這個引數有三種可能:

(1)永遠等待下去:僅在有乙個描述字準備好i/o時才返回。為此,把該引數設定為空指標null。

(3)根本不等待:檢查描述字後立即返回,這稱為輪詢。為此,該引數必須指向乙個timeval結構,而且其中的定時器值必須為0。

3、測試程式

寫乙個tcp回射程式,程式的功能是:客戶端向伺服器傳送資訊,伺服器接收並原樣傳送給客戶端,客戶端顯示出接收到的資訊。

服務端程式如下所示:

#include #include #include #include #include #include #include #include #include #define ipaddress   "127.0.0.1"

#define port 8787

#define maxline 1024

#define listenq 5

//函式宣告

//建立套接字並進行繫結

static int socket_bind(const char* ip,int port);

//io多路復用select

static void do_select(int listenfd);

//處理多個連線

static void handle_connection(int *connfds,int num,fd_set *prset,fd_set *pallset);

int main(int argc,char *argv)

static int socket_bind(const char* ip,int port)

bzero(&servaddr,sizeof(servaddr));

servaddr.sin_family = af_inet;

inet_pton(af_inet,ip,&servaddr.sin_addr);

servaddr.sin_port = htons(port);

if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1)

return listenfd;

}static void do_select(int listenfd)

//測試監聽描述符是否準備好

if (fd_isset(listenfd,&rset))

}fprintf(stdout,"accept a new client: %s:%d\n", inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);

//將新的連線描述符新增到陣列中

for (i = 0;i maxfd ? connfd : maxfd);

//記錄客戶連線套接字的個數

maxi = (i > maxi ? i : maxi);

if (--nready <= 0)

continue;

}//處理客戶連線

handle_connection(clientfds,maxi,&rset,&allset);

}}static void handle_connection(int *connfds,int num,fd_set *prset,fd_set *pallset)

printf("read msg is: ");

write(stdout_fileno,buf,n);

//向客戶端傳送buf

write(connfds[i],buf,n);}}

}

客戶端程式如下:

#include #include #include #include #include #include #include #include #include #define maxline     1024

#define ipaddress "127.0.0.1"

#define serv_port 8787

#define max(a,b) (a > b) ? a : b

static void handle_connection(int sockfd);

int main(int argc,char *argv)

static void handle_connection(int sockfd)

write(stdout_fileno,recvline,n);

}//測試標準輸入是否準備好

if (fd_isset(stdin_fileno,&rset))

write(sockfd,sendline,n);}}

}

4、程式結果

啟動服務程式,執行兩個客戶程式進行測試,結果如下圖所示:

阻塞式i/o程式設計有兩個特點: 

一、如果乙個發現i\o有輸入,讀取的過程中,另外乙個也有了輸入,這時候不會產生任何反應,也就是需要你的程式語句去select的時候才知道有資料輸入。 

二、程式去select的時候,如果沒有資料輸入,程式會一直等待,直到有資料位置,也就是程式中無需迴圈和sleep。

IO多路復用之select總結

io 多路復用是指核心一旦發現程序指定的乙個或者多個io條件準備讀取,它就通知該程序。io多路復用適用如下場合 1 當客戶處理多個描述字時 一般是互動式輸入和網路套介面 必須使用i o復用。2 當乙個客戶同時處理多個套介面時,而這種情況是可能的,但很少出現。3 如果乙個tcp伺服器既要處理監聽套介面...

IO多路復用之select總結

io多路復用是指核心一旦發現程序指定的乙個或者多個io條件準備讀取,它就通知該程序。io多路復用適用如下場合 1 當客戶處理多個描述字時 一般是互動式輸入和網路套介面 必須使用i o復用。2 當乙個客戶同時處理多個套介面時,而這種情況是可能的,但很少出現。3 如果乙個tcp伺服器既要處理監聽套介面,...

I O多路復用之select總結

1 基本概念 io多路復用是指核心一旦發現程序指定的乙個或者多個io條件準備讀取,它就通知該程序。io多路復用適用如下場合 1 當客戶處理多個描述字時 一般是互動式輸入和網路套介面 必須使用i o復用。2 當乙個客戶同時處理多個套介面時,而這種情況是可能的,但很少出現。3 如果乙個tcp伺服器既要處...