多路複用I/O模型之select
1 .所謂I/O多路複用是指核心一旦發現程序指定的一個或者多個I/O條件準備讀取,它就通知該程序。I/O多路複用適用如下場合:
(1)當客戶處理多個描述字時(一般是互動式輸入和網路套介面),必須使用I/O複用。
(2)當一個客戶同時處理多個套介面時,而這種情況是可能的,但很少出現。
(3)如果一個TCP伺服器既要處理監聽套介面,又要處理已連線套介面,一般也要用到I/O複用。
(4)如果一個伺服器即要處理TCP,又要處理UDP,一般要使用I/O複用。
(5)如果一個伺服器要處理多個服務或多個協議,一般要使用I/O複用。
2 .在多路I/O複用的場合中,應用程式需要同時處理多路輸入流和輸出流,若我們採用阻塞的模式,則達不到預期的目的;若採用非阻塞的模式,對多個輸入進行輪詢,會很浪費cpu 的時間;若採用多程序/多執行緒來處理這樣的問題,會使程式變得更加複雜,並且不易維護;因此最好的方法就是採用“多路I/O複用”。
3 .select函式
該函式允許程序指示核心等待多個事件中的任何一個發生,並只在有一個或多個時間發生或經歷一段指定的時間後才喚醒;
該函式原型為:
int select(int nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);
所需要標頭檔案:
/* According to POSIX.1-2001 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
函式說明:
select()函式用來等待檔案描述符狀態的改變。引數nfds代表最大的檔案描述符+1,引數readfds、writefds、execptfds稱為“描述符組”,用來傳回描述符的讀、寫或或異常的狀況;
select中各引數含義:
nfds:表示集合中需要檢查的號碼最高的檔案描述符+1
readfds:由select()函式監聽的讀檔案描述符集合
writefds:由select()函式監聽的寫檔案描述符集合
execptfds:由select()函式監視的異常處理檔案描述符集合
timeout:
對於timeout;它是一個結構體指標,原型為:struct timeval *timeout;這個時間結構體的精確度可以設定到微妙級。該結構體如下:
struct timeval *timeout{
long tv_sec; /* second 秒 */
long tv_unsec; /* and microseconds 微秒 */
}
該結構體的變數設定有3種情況:
1.
NULL:表示“永遠等待”。直到捕捉到訊號或檔案描述符已經準
備好為止。如果捕捉到一個訊號,則select返回-1,errno
設定為EINTR;
2.
timeout->tv_sec == 0 && timeout->tv_usec == 0;
表示“完全不等待”;測試所有已指定的描述符並立即返回。這是
得到多個描述符的狀態而不阻塞select函式的輪詢方法;
3.
timeout->tv_sec != 0 && timeout->tv_usec != 0;
表示“等待指定的秒數和微秒數”。當指定的描述符之一(readfds
、writefds或execptfds)已經準備好,或當指定的時間值已經
超過了的時候則立即返回。如果在超時時候還沒有一個檔案描述符
已經準備好,則返回值為0;
select函式是一個阻塞的函式,當select函式返回時,也就是有檔案描述符可以讀寫資料的時候,此時可以用讀寫函式完成資料的讀寫;其返回值表示有多少個檔案有訊息;和阻塞模式相比,多路複用技術的高階之處就在於能夠同時去等待多個檔案描述符,當這些檔案描述符中的任意一個進入就緒狀態時,select函式就可以返回。
結論:select函式是一個“阻塞”函式,當該函式執行時,必定會有下面2個事件中的一個;
1.select監測的檔案I/O集合中,有檔案有訊息
2. 時間超時,通過select的第5個引數指定超時的時間
4 .在使用select函式的時候需要對檔案描述符進行分類別處理,當檔案描述符的處理主要涉及到4個巨集函式;分別是:
select檔案描述符集處理巨集
/* 清除一個檔案描述符集合 */
FD_ZERO(fd_set *set)
/* 將一個檔案描述符加入檔案描述符集合中 */
FD_SET(int fd, fd_set *set)
/* 將一個檔案描述符從檔案描述符集合中清除*/
FD_CLR(int fd, fd_set *set)
/* 測試該集合中的一個檔案描述符有無傳送變化 */
FD_ISSET(int fd, fd_set *set)
通常,在使用select函式之前,首先應該呼叫FD_ZERO 和FD_SET
來初始化檔案描述符集,在使用了select函式時,可以迴圈使用F_ISSET來測試哪一個檔案描述符就緒,在執行完相關的檔案描述符
之後,可使用FD_CLR來清除該檔案描述符。
5 .select函式的原理為:
從set集合中挑選出有資料的fd,一旦set集合中有檔案描述符傳送狀態改變,則select立刻退出阻塞狀態,然後繼續向下執行相應的操作。
6 .示例 1
linux的/dev/input/下分別有一個mice滑鼠讀寫事件檔案和event1鍵盤讀寫事件檔案;當用open開啟這兩個檔案,並且對其進行讀操作時,都是一個阻塞的操作;即當鍵盤的按鍵被按下,或者滑鼠被點選的時候,才會解除阻塞,開始讀寫;現在用select的i/o複用模型知識來解決這個問題;用一個程序(主程式)來處理,當有鍵盤讀寫時候,立刻去呼叫個鍵盤列印函式;若有滑鼠讀寫時,立刻執行滑鼠的列印函式;
有兩個注意的地方:
(1) 需要修改/dev/input/mice 和 /dev/input/event1這
兩個檔案的許可權
(2) 在列印滑鼠響應事件和鍵盤響應事件的地方,每次把set裡面
的值取出來,不然每次來判斷裡面都有資料,會陷入一個死迴圈中;
結果:當有滑鼠被按下的時候,列印“滑鼠被響應....”;當有鍵盤被
按下的時候,列印“鍵盤被響應....”;
/*************************************************************************
* File Name: select.c
* Author: The answer
* Function: Other
* Mail: [email protected]
* Created Time: 2017年06月16日 星期五 16時14分19秒
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<signal.h>
#include<time.h>
#include<unistd.h>
void sys_err(const char *ptr,int num)
{
perror(ptr);
exit(num);
}
int main(int argc,char **argv)
{
int fd_mice = open("/dev/input/mice",O_RDONLY);
if(fd_mice < 0)
sys_err("open mice",-1);
int fd_key = open("/dev/input/event1",O_RDONLY);
if(fd_key < 0)
sys_err("open keyboard",-2);
while(1)
{
struct timeval timeout;
fd_set set;
int maxfd;
/* 取出兩個檔案描述符中的最大者 */
maxfd = fd_mice > fd_key ? fd_mice : fd_key;
/* 初始化集合set */
FD_ZERO(&set);
/* 在set集合中加入相應的描述集 */
FD_SET(fd_mice,&set);
FD_SET(fd_key, &set);
/* 設定select阻塞等待最長的時間(秒數) */
timeout.tv_sec = 5;
timeout.tv_usec = 0;
/* select有準備就緒的檔案描述符就返回,否則等待
* 5秒後報錯
* */
int ret = select(maxfd + 1,&set,NULL,NULL,&timeout);
if(ret == 0 )
{
printf("time out\n");
continue;
//表示被訊號中端給打斷
}else if(ret == -1 && errno == EINTR){
printf("signal inturrupt\n");
continue;
}else if(ret == -1)
{
printf("bad error\n");
break;
}else if(ret > 0)
{
char buf[1024];
/* bzero將buf中的sizeof(buf)位元組空間全部清零 */
bzero(buf,sizeof(buf));
if(FD_ISSET(fd_key,&set))
{
printf("鍵盤有訊息....\n");
/* 記得將資料讀出,不然會死迴圈 */
read(fd_key,buf,sizeof(buf));
}
if(FD_ISSET(fd_mice,&set))
{
puts("滑鼠有訊息....\n");
/* 記得將資料讀出,不然會死迴圈 */
read(fd_mice,buf,sizeof(buf));
}
}
}
}
示例2:
相關推薦
多路複用I/O模型之select
1 .所謂I/O多路複用是指核心一旦發現程序指定的一個或者多個I/O條件準備讀取,它就通知該程序。I/O多路複用適用如下場合: (1)當客戶處理多個描述字時(一般是互動式輸入和網路套介面),必須使用I/O複用。 (2)當一個客戶同時處理多個套介面時,
多路複用I/O--epoll
多路複用I/O–epoll epoll定義 epoll只有epoll_create,epoll_ctl,epoll_wait 3個系統呼叫。 int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, s
多路複用I/O--select
多路複用I/O–select select定義 #include <sys/select.h> int select(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *res
嵌入式Linux網路程式設計,I/O多路複用,阻塞I/O模式,非阻塞I/O模式fcntl()/ioctl(),多路複用I/O select()/pselect()/poll(),訊號驅動I/O
文章目錄 1,I/O模型 2,阻塞I/O 模式 2.1,讀阻塞(以read函式為例) 2.2,寫阻塞 3,非阻塞模式I/O 3.1,非阻塞模式的實現(fcntl()函式、ioctl() 函式)
淺析epoll-為何多路複用I/O要使用epoll
本文轉自C++愛好者部落格 http://www.cppfans.org/author/eliteyang,順便記錄一下自己學習epoll的過程。 現如今,網路通訊中用epoll(linux)和IOCP(windows)幾乎是大家津津樂道的東西,不為別的,就因為高效
併發伺服器:多路複用I/O
在實際的應用中,要求一個伺服器能同時處理大量的客戶請求,所有這些客戶將訪問綁 定在某一個特定套接字地址上的伺服器。因此,伺服器必須滿足併發的需求。如果不採用並 發技術,當伺服器處理一個客戶請求時,會拒絕其他客戶端請求,造成其他客戶要不斷的請 求並長期等待。 在Linux(Unix)系統中併發伺服器有三種設計方
Java網路程式設計與NIO詳解2:JAVA NIO 一步步構建I/O多路複用的請求模型
微信公眾號【黃小斜】作者是螞蟻金服 JAVA 工程師,專注於 JAVA 後端技術棧:SpringBoot、SSM全家桶、MySQL、分散式、中介軟體、微服務,同時也懂點投資理財,堅持學習和寫作,相信終身學習的力量!關注公眾號後回覆”架構師“即可領取 Java基礎、進階、專案和架構師等免費學習資料,更有資料
http協議,阻塞IO,非阻塞IO,IO多路複用,位運算,select方法
HTTP請求 Request 請求格式: 請求行 GET / HTTP/1.1 請求種類  
Linux網路程式設計---I/O多路複用之select
1.I/O多路複用(IO multiplexing) 我們之前講了I/O多路複用和其他I/O的區別,在這裡,我們再具體討論下I/O多路複用是怎麼工作? I/O 多路複用技術就是為了解決程序或執行緒阻塞到某個 I/O 系統呼叫而出現的技術,使程序不阻塞於某個特定的 I/O 系統呼叫。
I/O多路複用之select、poll、epoll
很早之前有寫過篇IO多路複用的文章:https://www.cnblogs.com/klcf0220/archive/2013/05/14/3077003.html 參考連結:https://segmentfault.com/a/1190000003063859 select,poll,epoll都是IO多路
IO基礎入門之I/O多路複用技術
在I/O程式設計過程中,當需要同時處理多個客戶端接入請求時,可以利用多執行緒或者I/O多路複用技術進行處理。I/O多路複用技術通過把多個I/O的阻塞複用到同一個select的阻塞上,從而使得系統在單執行緒的情況下可以同時處理多個客戶端請求。與傳統的多執行緒/多程序模型比,I
淺談網路I/O多路複用模型 select & poll & epoll
我們首先需要知道select,poll,epoll都是IO多路複用的機制。I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,
I/O多路複用之 epoll 系統呼叫
I/O多路複用除了之前我們提到的select和poll外,epoll 也可以檢查多個檔案描述符的就緒狀態,以達到I/O多路複用的目的。 epoll 系統呼叫是 Linux 系統專有的,在 Linux 核心 2.6 版本新增,epoll 的主要優點有: 當檢
Socket網路程式設計_之I/O多路複用
1. IO多路複用: 每一次網路通訊都是一個Socket的I/O流,對於伺服器而言,有兩種方法 1.傳統的多程序併發模型(每進來一個新的I/O流會分配一個新的程序管理。) 2.方法二就是I/O的多路複用
I/O多路複用之水平觸發和邊沿觸發模式
多路I/O複用不管是select,poll還是epoll,其都是通過同時監聽多個檔案描述符,當有檔案檔案描述符處於就緒狀態時,觸發通知。 LT(Level Trigger,水平觸發)模式和ET(Edge Trigger,邊沿觸發)模式是兩種檔案描述符準備就緒的
Linux網路程式設計---I/O多路複用之epoll
/* TCP伺服器 用法:./server port */ #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <string
java併發程式設計之IO基礎入門之I/O多路複用技術
在I/O程式設計過程中,當需要同時處理多個客戶端接入請求時,可以利用多執行緒或者I/O多路複用技術進行處理。I/O多路複用技術通過把多個I/O的阻塞複用到同一個select的阻塞上,從而使得系統在單執行緒的情況下可以同時處理多個客戶端請求。與傳統的多執行緒/多程序模型比,
I/O多路複用模型
背景 在文章《unix網路程式設計》(12)五種I/O模型中提到了五種I/O模型,其中前四種:阻塞模型、非阻塞模型、訊號驅動模型、I/O複用模型都是同步模型;還有一種是非同步模型。 想寫一個系列的文章,介紹從I/O多路複用到非同步程式設計和RPC框架,整個演進過程,這一系列可能包括: I/O多路複用模型 e
詳解Go語言I/O多路複用netpoller模型
> 轉載請宣告出處哦~,本篇文章釋出於luozhiyun的部落格:https://www.luozhiyun.com > > 本文使用的go的原始碼15.7 可以從 Go 原始碼目錄結構和對應程式碼檔案瞭解 Go 在不同平臺下的網路 I/O 模式的實現。比如,在 Linux 系統下基於 epoll,free
從網路I/O模型到Netty,先深入瞭解下I/O多路複用
微信搜尋【阿丸筆記】,關注Java/MySQL/中介軟體各系列原創實戰筆記,乾貨滿滿。 本文是Netty系列第3篇 上一篇文章我們瞭解了Unix標準的5種網路I/O模型,知道了它們的核心區別與各自的優缺點。尤其是I/O多路複用模型,在高併發場景下,有著非常好的優勢。而Netty也採用了I