1. 程式人生 > >多路複用I/O模型之select

多路複用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/Oselect

1.I/O多路複用(IO multiplexing) 我們之前講了I/O多路複用和其他I/O的區別,在這裡,我們再具體討論下I/O多路複用是怎麼工作? I/O 多路複用技術就是為了解決程序或執行緒阻塞到某個 I/O 系統呼叫而出現的技術,使程序不阻塞於某個特定的 I/O 系統呼叫。

I/Oselect、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/Oepoll

/* 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/Onetpoller模型

> 轉載請宣告出處哦~,本篇文章釋出於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