zoukankan      html  css  js  c++  java
  • I/O多路复用

    I/O模型 参考链接:http://www.cnblogs.com/klcf0220/p/3208890.html

    I/O复用典型地用在下列网络应用场合:
    1.当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。
    2.一个客户同时处理多个套接口是可能的,但是很少出现。
    3. 如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。
    4. 如果一个服务器既要处理TCP,又要处理UDP,一般也要使用I/O复用。
    5. 如果一个服务器要处理多个服务或者多个协议,一般要使用I/O复用。

    select函数

    select()系统调用可以使进程检测同时等待的多个I/O设备,当没有设备准备好时,select()阻塞,其中任一设备准备好时,select()就返回。

    #include <sys/select.h>
    #include <sys/time.h>
    int select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
        const struct timeval *timeout);

    select的第一个参数是文件描述符集中要被检测的比特数,这个值必须至少比待检测的最大文件描述符大1;参数readfds指定了被读监控的文件描述符集;参数writefds指定了被写监控的文件描述符集;而参数exceptfds指定了被例外条件监控的文件描述符集。参数timeout起了定时器的作用:到了指定的时间,无论是否有设备准备好,都返回调用。

    timeval的结构定义如下:
    struct timeval{
        long tv_sec; //表示几秒
        long tv_usec; //表示几微妙
    }

    timeout取不同的值,该调用就表现不同的性质:

    1.timeout为0,调用立即返回;
    2.timeout为NULL,select()调用就阻塞,直到知道有文件描述符就绪;
    3.timeout为正整数,就是一般的定时器。

    select调用返回时,除了那些已经就绪的描述符外,select将清除readfds、writefds和exceptfds中的所有没有就绪的描述符。select的返回值有如下情况:
    1.正常情况下返回就绪的文件描述符个数;
    2.经过了timeout时长后仍无设备准备好,返回值为0;
    3.如果select被某个信号中断,它将返回-1并设置errno为EINTR。
    4.如果出错,返回-1并设置相应的errno。

    系统提供了4个宏对描述符集进行操作:

    #include <sys/select.h>
    #include <sys/time.h>
     void FD_SET(int fd, fd_set *fdset);
     void FD_CLR(int fd, fd_set *fdset);
     void FD_ISSET(int fd, fd_set *fdset);
     void FD_ZERO(fd_set *fdset);

    宏FD_SET设置文件描述符集fdset中对应于文件描述符fd的位(设置为1),宏FD_CLR清除文件描述符集 fdset中对应于文件描述符fd的位(设置为0),宏FD_ZERO清除文件描述符集fdset中的所有位(既把所有位都设置为0)。使用这3个宏在调用select前设置描述符屏蔽位,在调用select后使用FD_ISSET来检测文件描述符集fdset中对应于文件描述符fd的位是否被设置。

    select的使用方法:

    1. 将要监控的文件添加到文件描述符集
    2. 调用select开始监控
    3. 判断文件是否发生变化。       

    FD_ZERO(&fds); //清空集合
    FD_SET(fd1,&fds); //设置描述符
    FD_SET(fd2,&fds); //设置描述符
    maxfdp=fd1+1; //描述符最大值加1,假设fd1>fd2
    switch(select(maxfdp,&fds,NULL,NULL,&timeout))
    case -1: exit(-1);break; //select错误,退出程序
    case 0:break;
    default:if(FD_ISSET(fd1,&fds)).... //测试fd1是否可读

    可运行源代码:

    #include<sys/time.h>
    #include<sys/types.h>
    #include <unistd.h>
    #include<stdio.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include<stdlib.h>
    #define TIMEOUT 5
    #define BUF_LEN 1024
    
    int max(int a,int b){
        return (a>b)?a:b;
    }
    
    int main(void)
    {
        struct timeval tv;
        fd_set readfds;
        int fd_open, fd ,maxfdp1;
        int ret;
        fd_open = open("select_test.c",O_RDONLY);
        FD_ZERO(&readfds);
        FD_SET(STDIN_FILENO, &readfds);
        FD_SET(fd_open, &readfds);
        tv.tv_sec = TIMEOUT;
        tv.tv_usec = 0;
        maxfdp1 = max(STDIN_FILENO  , fd_open) + 1;  //注意要加1
        ret = select(maxfdp1,&readfds,NULL,NULL,    &tv);
        if(ret == -1)
        {
            perror("select");
            return 1;
        }
        else if(!ret){
            printf("%d seconds elapsed.\n",TIMEOUT);
            return 0;
        }
        if (FD_ISSET(STDIN_FILENO, &readfds)){
            char buf[BUF_LEN+1];
            int len;
            len = read(STDIN_FILENO,buf,BUF_LEN);
            if(len == -1)
            {
                perror("read");
            }
            if(len){
                buf[len] = '\0';
                printf("read:%s\n",buf);
            }
        }
        if (FD_ISSET(fd_open, &readfds)){
            char buf[BUF_LEN+1];
            int len;
            len = read(fd_open,buf,BUF_LEN);
            if(len == -1){
                perror("read");
            }
            if(len)
            {
                buf[len] = '\0';
                printf("read:%s\n",buf);
            }
        }
        fprintf(stderr,"This should not happen!\n");
        return 1;
    }

    GCC编译通过,可以自行测试运行,本程序测试了两个描述符,一个标准输入,一个是文件描述符。

    pselect函数

    #include <sys/select.h>
    #include <signal.h>
    #include <time.h>
    int pselect(int maxfdp1, fd_set * readset, fd_set * writeset, fd_set * exceptset, const struct timespec * timeout, const sygset_t * sigmask); 
    // 返回: 准备好描述字的个数, 0-超时 -1-出错

    poll函数

    poll提供了与select相似的功能,但当涉及到流设备时,它还提供了附加信息。

    #include <poll.h>
    int poll(struct pollfd * fdarray, unsigned long nfds, int timeout); // 返回: 准备好描述字的个数, 0-超时, -1-出错
  • 相关阅读:
    HDU 4539郑厂长系列故事――排兵布阵(状压DP)
    HDU 2196Computer(树形DP)
    HDU 4284Travel(状压DP)
    HDU 1520Anniversary party(树型DP)
    HDU 3920Clear All of Them I(状压DP)
    HDU 3853LOOPS(简单概率DP)
    UVA 11983 Weird Advertisement(线段树求矩形并的面积)
    POJ 2886Who Gets the Most Candies?(线段树)
    POJ 2828Buy Tickets
    HDU 1394Minimum Inversion Number(线段树)
  • 原文地址:https://www.cnblogs.com/klcf0220/p/3077003.html
Copyright © 2011-2022 走看看