Linux I/O複用——select系統調用

Linux中I/O複用使得程序能夠同時監聽多個文件描述符,這對提高程序的性能至關重要。
Linux下實現I/O複用的系統調用主要有select、poll、epoll。
select系統調用
select的主要用途是:在一段時間內,監聽用戶感興趣的文件描述符上的可讀,可寫和異常事件。

1.select原型

#include<sys/select.h>
int select(int nfds,fd_set *readfd,fd_set *writefd,fd_set *exceptfds,struct timeval *timeout);
  1. 參數含義
    (1)nfds:指定被監聽的文件描述符的總數。通常需要加一,因爲文件描述符都從0開始。
    (2)readfd,writefd,exceptfds分別指向可讀,可寫和異常事件對應的文件描述符的集合。
    我們通常使用以下的宏來訪問fd_set結構體中的位:
    fd_set結構體中共有1024個位,也就是說最多能容納1024個文件描述符,1位表示一個文件描述符。
#include<sys/select.h>
FD_ZEOR(fd_set *fdset);  //清楚集合中的所有位
FD_SET(int fd,fd_set *fdset);//設置集合的位
FD_CLR(int fd,fd_set *fdset);//清空集合所有位
FD_ISEET(int fd,fd_set *fdset);//測試集合中的位裏是否有數據

(3)timeout表示可超時的時間。不過我們不能完全相信select調用之後的返回值,比如timeout調用返回失敗後的值是不確定的。timeval結構體的定義如下:

struct timeval
{
    long tv_sec;  //秒數
    long tv_usec; //微秒數
};

如果給timeval的兩個成員變量都傳0,則select立即返回,如果給timeout傳遞NULL,則select會一直阻塞,直到有某個文件描述符就緒。
3.函數返回值
(1)如果select成功時就返回文件描述符的總數。
(2)如果在超時時間內沒有任何文件描述符就緒,就返回0.
(3)失敗返回-1並設置error。
(4)如果在select等待期間,程序接受信號,則邏輯返回-1,並設置EINTR.
4.理解select模型
理解select模型的關鍵在於理解fd_set,爲說明方便,取fd_set長度爲1字節,fd_set中的每一bit可以對應一個文件描述符fd。則1字節長的fd_set最大可以對應8個fd。
(1)執行fd_set set; FD_ZERO(&set);則set用位表示是0000,0000。
(2)若fd=5,執行FD_SET(fd,&set);後set變爲0001,0000(第5位置爲1)
(3)若再加入fd=2,fd=1,則set變爲0001,0011
(4)執行select(6,&set,0,0,0)阻塞等待
(5)若fd=1,fd=2上都發生可讀事件,則select返回,此時set變爲0000,0011。注意:沒有事件發生的fd=5被清空。
5.編程實例
使用select函數編寫一個程序,5秒之內不在屏幕上輸入數據則打印出超時,否則打印出內容

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<sys/select.h>
#include<sys/time.h>


int main()
{
    int fd = 0;
    fd_set fdset;
    while(1)
    {
        FD_ZERO(&fdset);
        FD_SET(fd,&fdset);
        FD_CLR(fd,&fdset);
        struct timeval tv = {5,0};

        int n = select(fd+1,&fdset,NULL,NULL,&tv);
        if(n == 0)
        {
            printf("time out\n");
        }
        else if(n == -1)
        {
            perror("select error");
            continue;
        }
        else
        {
            if(FD_ISSET(fd,&fdset) == 0)
            {
                char buff[128] = {0};
                read(fd,buff,127);
                printf("read=%s\n",buff);
            }
        }
    }
}

結果:這裏寫圖片描述

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