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-出错
  • 相关阅读:
    hdu2860 并查集模拟
    hdu 3938 Portal离线并查集
    hdu 2489 Minimal Ratio Tree (DFS枚举+MST)
    hdu 3172 并查集+map
    hdu 1829 A Bug's Life 并查集系列
    hdu 1598 find the most comfortable road
    HDU1198
    【Oracle】【17】表创建后,对表进行操作(添加字段,删除主键约束等)
    【JS】【19】使用Jquery判断是电脑或手机或微信浏览器访问
    【JS】【18】当前时间加减一天和格式化时间格式
  • 原文地址:https://www.cnblogs.com/klcf0220/p/3077003.html
Copyright © 2011-2022 走看看