socket之IO多路復用總結

2021-08-20 23:58:50 字數 3783 閱讀 6839

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

因為檔案描述符是從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;

這個引數有三種可能:

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

(2)等待固定時長:在有乙個描述字準備好i/o時返回,但是不超過由該引數所指向的timeval結構中指定的秒數和微秒數。

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

原理圖:

/*乙個埠釋放後會等待兩分鐘之後才能再被使用,so_reuseaddr是讓埠釋放後立即就可以被再次使用。*/

int reuse = 1;

if (setsockopt(fd, sol_socket, so_reuseaddr, &reuse, sizeof(reuse)) == -1)

bzero(&server_addr, sizeof(struct sockaddr_in));

server_addr.sin_family = af_inet;

server_addr.sin_addr.s_addr = ip;

server_addr.sin_port = htons(port);

/* 繫結本地ip與埠 */

if(-1 == bind(fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)))

/* 監聽網路 */

if(-1 == listen(fd, max_listen_num))

return fd;

}static int accept_client_proc(int server_fd)

else

}fprintf(stdout, "accept a new client: %s:%d\n",

inet_ntoa(client_addr.sin_addr), client_addr.sin_port);

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

int i = 0;

for(i = 0; i < max_cli_num; i++) }

if(i == max_cli_num)

return 0;

}static int handle_client_msg(int fd, char *buf)

static void recv_client_msg(fd_set *prfds)

; for(i = 0; i <= srv_ctx.cli_cnt; i++)

/*判斷客戶端套接字是否有資料*/

if(fd_isset(client_fd, prfds))

handle_client_msg(client_fd, buf);

} }}static void handle_client_proc(int server_fd)

srv_ctx.maxfd = (client_fd > srv_ctx.maxfd ? client_fd:srv_ctx.maxfd);

} /* 開始輪詢接收處理服務端和客戶端套接字 */

retval = select(srv_ctx.maxfd + 1, prfds, null, null, &tv);

if(-1 == retval)

if(0 == retval)

if(fd_isset(server_fd, prfds))

else

}}static int server_init(void)

return 0;

}int main(int argc, char *argv)

else

/* 獲取監聽埠 */

if(argv[2])

else

server_init();

fd_srv = create_server_proc(ip, port);

while(1)

close(fd_srv);

return 0;

}

IO多路復用總結

講io多路復用之前我們先理解什麼是io?我們都知道unix世界裡,一切皆檔案,而檔案是什麼呢?檔案就是一串二進位製流,不管socket,還是fifo 管道 終端,對我們來說,一切都是檔案,一切都是流。在資訊 交換的過程中,我們都是對這些流進行資料的收發操作,簡稱為i o操作 input and ou...

I O多路復用

一 五種i o模型 1 阻塞i o模型 最流行的i o模型是阻塞i o模型,預設情形下,所有套介面都是阻塞的。我們以資料報套介面為例來講解此模型 我們使用udp而不是tcp作為例子的原因在於就udp而言,資料準備好讀取的概念比較簡單 要麼整個資料報已經收到,要麼還沒有。然而對於tcp來說,諸如套介面...

i o多路復用

最常見的i o多路復用就是 select poll epoll了,下面說說他們的一些特點和區別吧。select 可讀 可寫 異常三種檔案描述符集的申明和初始化。fd set readfds,writefds,exceptionfds fd zero readfds fd zero writefds ...