Linux IO模型 : select

前言:爲什麼要使用IO多路轉接模型?

試想一下,如果A想接收B的消息,那麼A就需要創建一個進程(或線程),用while(1)循環一直監視B是否給A發來消息,同時B也一直需要監視A,這會讓系統的開銷變得很大。
IO多路轉接模型的函數select, 可以幫助我們同時監視多個文件句柄, 這樣極大地降低了 內存 與 CPU 的開銷。

IO多路轉接模型

  • int select(int maxFd, fdset* rdset, fdset* wrset, fdset* exceptionset, struct timeval*)
    select函數的本質:將加入的文件句柄進行監視, 如果讀集合有可讀的情況 或者 寫集合有可寫的情況,那麼將向下執行
    出錯時返回 -1
    超時返回 0
    正常情況下返回一個 大於0 的數

參數說明
maxfd: 文件句柄的最大值+1,如0, 1, 2分別代表輸入,輸出,錯誤輸出,那麼maxfd應該是現有的fd的最大值+1, select的本質是循環

rdset: 讀文件句柄的集合,當檢測的文件句柄中有可讀的情況時,開始往下執行

wrset: 寫文件句柄的集合,當檢測的文件句柄中有可寫的情況時,開始往下執行,一般來說文件句柄均爲可寫的情況

exceptionset: 異常文件句柄的集合

struct timeval:等待時間 NULL表示select函數阻塞並無限等待,0表示select函數非阻塞不等待,傳入timeval則表示阻塞等待的時間

文件句柄的函數:

  • FD_ZERO(fd_set* sets)
    清空sets集合中原來的文件句柄
  • FD_SET(int fd, fd_set* sets)
    添加文件句柄到集合中
  • FD_ISSET(int fd, fd_set* sets)
    判斷文件句柄在sets集合中是否有設定

實例 :兩個文件句柄,同時對pipe文件進行讀取和寫入

char *GenerateStr(char *str, int strlen)
{
    int i, flag;

    srand(time(NULL)); //通過時間函數設置隨機數種子,使得每次運行結果隨機。
    for (i = 0; i < strlen; i++)
    {
        flag = rand() % 3;
        switch (flag)
        {
        case 0:
            str[i] = rand() % 26 + 'a';
            break;
        case 1:
            str[i] = rand() % 26 + 'A';
            break;
        case 2:
            str[i] = rand() % 10 + '0';
            break;
        }
    }
    str[strlen] = 0;
    return str;
}

int test1()
{
    int fdr = open("pipe", O_RDWR);
    ERROR_CHECK(fdr, -1, "pipe");
    int fdw = open("pipe", O_RDWR);
    ERROR_CHECK(fdw, -1, "pipe");
    fd_set rdset, wrset;
    struct timeval timeout;
    while (1)
    {
        FD_ZERO(&rdset);
        FD_ZERO(&wrset);
        FD_SET(fdr, &rdset);
        FD_SET(fdw, &wrset); //爲了防止文件句柄與初始狀態相比發生變化,所以每一次都要重新清空再設置
        timeout.tv_sec = 3;
        timeout.tv_usec = 0;
        int ret = select(5, &rdset, &wrset, NULL, &timeout);
        if (ret > 0)
        {
            if (FD_ISSET(fdw, &wrset))
            {
                cout << "fdw write:" << endl;
                char buf[20] = {0};
                GenerateStr(buf, 10);
                write(fdw, buf, strlen(buf));
                cout << endl;
            }
            if (FD_ISSET(fdr, &rdset))
            {
                cout << "fd1 read:" << endl;
                char buf[20] = {0};
                read(fdr, buf, sizeof(buf));
                sleep(1);
                cout << buf << endl;
            }
        }
        else
            cout << "timeout" << endl;//因爲設置了寫集合,所以實際上不會出現超時的情況,因爲文件句柄隨時都是可寫的狀態
    }
    close(fdw);
    close(fdr);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章