多路轉接select1

高級IO

通常情況下所有的 IO 都可以分爲兩步來完成, 第一步等待, 第二步數據搬遷, 爲了提高 IO 效率通常所運用的方法就是減少等待的時間

舉個釣魚的例子

現在有五個人張三, 李四, 王五, 趙六, 錢七. 它們五個人來到湖邊來釣魚. 而它們五個人的釣魚方各不相同.
張三釣魚方法:
往魚鉤上掛上魚餌, 然後一動不動地盯着魚餌, 不管有任何人來叫張三, 張三誰都不理, 唯一關注的就是是否有魚上鉤, 於是就一直盯着魚漂, 只要魚漂有動靜, 就說明有魚上鉤, 於是將上鉤的魚拉上來.
李四釣魚方法:
將魚餌往魚鉤上一掛, 將魚鉤和魚餌全部扔到河裏, 然後他一邊釣魚, 一邊玩手機, 然後問一下張三釣了多少魚, 但是張三一直關注的是自己的魚漂是否有動靜, 它根本就不理李四, 玩一會兒手機定期看一下是否有魚上鉤.
王五釣魚方法:
王五比較聰明, 他看到張三和李四兩個人一個在那裏傻傻地盯着魚漂, 一個像話嘮一樣一直問着旁邊的人,於是他相處了一個辦法, 他往掛魚餌的那個地方掛一個鈴鐺, 只要鈴鐺一響, 他便將魚從水裏拉出來. 如果鈴鐺沒有響, 自己該幹什麼就幹什麼.
趙六釣魚方法:
趙六相比前面的張三, 李四, 王五來說比較富裕, 他來的時候拿了好多個魚竿, 於是他將所有的魚竿往岸邊一插, 並且對這些魚竿進行編號, 然後不斷地對這些所有的魚竿進行便利檢測, 只要其中那個魚漂有動靜, 就將魚鉤拉上來.
錢七釣魚方法:
錢七是一個大土豪, 他來的時候是由自己的專門司機開着名車將自己帶過來的, 於是他將魚鉤交給自己的司機, 告訴他, 你幫我釣魚, 等你釣完魚, 下午的時候給我打電話, 我直接來拿魚就可以了. 於是去忙自己的事了.

總結

通過上面的這個例子, 我們可以看出來張三, 李四, 王五, 趙六他們都有一個特性, 那就是等待魚上鉤自己等待, 將魚拉上來也是自己幹, 而錢七相比前面的四個人而言也就是等待魚兒上鉤是別人替自己等, 魚拉上來也是別人幫自己拉上來, 而自己唯一要做的就是將釣魚這件事發起, 然後交給某個人就可以了.
如果將上面的釣魚的例子對應到我們的IO模型中的話, 那麼前四種就是對應的同步IO, 即等待和數據搬遷都由自己來完成, 而最後一種就是對應的異步 IO, 數據搬遷和等待都不需要自己來完成, 自己唯一干的就是發起某個事件.同時張三對應的IO模型就是阻塞方式, 李四就是非阻塞方式, 王五爲驅動方式, 趙六爲多路轉接模型, 錢七爲異步方式

幾個概念

同步IO事件由自己發起, 就緒事件的等待由自己完成, 數據的搬遷也是由自己來完成.

異步IO事件由自己發起, 就緒事件的等待, 數據的搬遷都由別人幫自己完成

輪詢不斷的檢測就緒事件是否發生, 輪詢是基於非阻塞接口.

IO多路轉接一次可以監視多個文件描述符, 就好比趙六一次可以監視多個魚竿

阻塞和非阻塞的不同

阻塞和非阻塞的不同之處在於等待方式的不同, 阻塞方式就是隻要就緒事件沒有發生, 則一直等待, 而非阻塞方式就是不斷檢測, 如果有就緒事件發生, 就處理就緒事件, 如果沒有就緒事件就返回, 然後過一段時間時間再進行檢測.

五種 IO 模型

阻塞方式在內核將數據準備好之間, 系統一直等待, 所有的套接字默認爲阻塞方式.

非阻塞方式需要程序員不斷循環反覆嘗試讀寫文件描述符.

信號驅動內核將數據準備好的時候, 於是便給當前應用程序發送一個SIGIO信號,當前應用進程收到這個信號的額時候, 於是便知道底層的就緒事件已經發生, 於是就進行 IO 操作

**IO多路轉接**IO多路轉接一次可以等待多個文件描述符的就緒事件

異步IO由內核在數據拷貝完成的時候通知應用進程(信號驅動對應的就是高速應用進程何時可以進行數據搬遷)

高級IO重要概念

同步IO VS 異步IO

同步IO在發出一個調用的時候, 在沒有得到結果之前, 該調用不會返回, 但是一旦調用返回, 就得到返回值, 即由調用者主動等待調用結果.

異步IO調用在發出之後, 這個調用就會返回, 沒有返回結果. 換言之就是當一個異步調用發出之後, 調用者不會立即等到結果, 而是在調用之後, 由被調用者通過狀態通知調用者, 或者通過回調函數來處理這個函數.

非阻塞相關接口

fcntl

我們都知道文件描述符默認都是阻塞 IO

#include<unistd.h>
#include<fcntl.h>

int fcntl(int fd, int cmd, .../*arg*/);

其中 fd 爲文件描述符, 表示要對哪一個文件描述符進行設置, cmd取值不同時代表了不同的方式

cmd = F_DUPFD 時代表複製一個文件描述符

cmd = FGETFD 或者 FSETFD 時代表獲得文件描述符標記

實現一個非阻塞文件描述符

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

void SetNoBlock(int fd)
{
    int f1 = fcntl(fd, F_GETFL);
    if(fd < 0)
    {
        perror("fd");
        exit(1);
    }
    fcntl(fd, F_SETFL, f1 | O_NONBLOCK);
}
int main()
{
    SetNoBlock(0);
    while(1)
    {
        char buf[1024] = {0};
        ssize_t s = read(0, buf, sizeof(buf));
        if(s < 0)
        {
            perror("read");//底層未將數據準備好
            sleep(1);
            continue;
        }
        printf("input %s\n", buf);
    }
    return 0;
}

重定向

曾近我們學習過將數據重定向即就是將某個文件符關閉, 然後打開文件描述符,此時對關閉的那個文件描述符進行操作便會成爲對文件的操作.

dup/dup2

#include <unistd.h>

int dup(int oldfd);

int dup2(int oldfd, int newfd);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章