多路IO复用 select 和 poll 函数简介

1、多路IO复用的概念
这里有一篇通俗易懂的文件介绍了多路IO的概念http://www.linuxidc.com/Linux/2013-03/80704.htm。当我们需要操作多个文件时,比如我们需要读多个套接字里面的内容,但我们并不知道什么时候套接字里会有数据,如果一直在某一个套接字上阻塞,这时候就不能处理其他套接字,这样会使实时性大打折扣。但是我们就想了,为什么不用非阻塞的方式,使用轮询的方式?轮询的方式确实可以实现,但效率低下,因为我们在需要不停的去“查看”里面有没有数据,即使里面什么也没有。于是我们就想有没有一种方法,在套接字里面有数据时就通知我们,让我们及时去处理,而没有数据时,我们可以不用去理,转而处理其他的事件,这就是多路IO由来。linux提供了以下两个函数来实现多路IO。
2、select函数

    头文件:
    #include<sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    函数原型:int select(int n, fd_set *readfds,
                        fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    还要搭配以下宏函数来使用
    FD_CLR(int fd, fd_set *set);
    FD_ISSET(int fd, fd_set *set);
    FD_SET(int fd , fd_set *set);
    FD_ZERO(fd_set *set);

参数说明
n : 所有的文件描述符中的最大值+1。
readfds:一个结构体指针,里面包含我们需要监测的发生“读”变化文件描述符
writefds:一个结构体指针,里面包含我们需要监测的发生“写”变化文件描述符
exceptfds:一个结构体指针,里面包含我们需要监测的发生“异常”变化文件描述符
timeout:设置时间的结构体
struct timeval{
long tv_sec; //秒数
long tv_usec;//毫秒数
}
FD_CLR(int fd, fd_set *set);:清除文件描述符集合中的一个fd
FD_SET(int fd , fd_set *set); :向文件描述符集合中添加一个fd
FD_ISSET(int fd, fd_set *set); :通过这个宏的返回值来判断哪一个文件出于”就绪”状态,可以来操作此文件。
FD_ZERO(fd_set *set); :清空文件描述符集合
应用举例:

/* 以下代码是读标准输入设备中的数据 */
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>

#define TIMEOUT 5
#define BUF_LEN 1024

int main(int argc, char const *argv[])
{
    struct timeval tv;  //设置时间的结构体
    fd_set readfds;     //文件描述符集合
    int ret ;

    FD_ZERO(&readfds);  //清空文件描述符集合
    FD_SET(STDIN_FILENO, &readfds);// 将文件描述符(标准输入:STDIN_FILENO)添加到集合中去

    /* 通过结构体来设置select 等待时间 */
    tv.tv_sec  = 5; //秒
    tv.tv_usec = 0; //微秒

    ret = select(STDIN_FILENO+1, &readfds, NULL, NULL, &tv);
    if(-1 == ret )
    {
        perror("select");
        return 1;
    }
    else if (ret == 0) //超出时间5s
    {
        printf("%d seconds elapsed.Nothing input!\n",TIMEOUT);
        return 0;
    }

    char buf[BUF_LEN+1];
    int len;
    if( FD_ISSET(STDIN_FILENO, &readfds) )//如果监测到有东西输入
    {
        len = read(STDIN_FILENO, buf, BUF_LEN);
        if(-1 == len)
        {
            perror("read");
            return 1;
        }
        else if (len != 0)
        {
            buf[len] = '\0';
            printf("read:%s\n", buf);
            /* code */
        }
        return 0;
    }
    fprintf(stderr, "This should not happen!\n");
    return 0;
}

3、poll函数

头文件:
#include<sys/poll.h>
函数原型:
int poll(struct pollfd *fds, unsigned int nfds, int timeout);

参数说明:
fds : 一个包含多个文件描述pollfd结构体的数组指针
struct pollfd{
int fd; //文件描述符
short events; //要监测的事件
short revents; //需要返回观察的事件
}
其中:events的可选项为
POLLIN : 没有数据可读
POLLRDNORM: 有正常的数据可读
POLLRDBAND :有优先的数据可读
POLLPRI :有高优先级的数据可读
POLLOU : 写操作不会阻塞
POLLWRNORM:写正常数据不会阻塞
POLLBAND : 写优先数据不会阻塞
POLLMSG : 有一个SIGPOLL消息可用
nfds : fds数组中有多少个结构体,fds也就是数组的大小
timeout : 设置时间,同select一样,不过这里的单位是毫秒
应用举例:

//以下程序使用poll函数实现监测标准输入,同select.c文件实现的功能是一样

#include <sys/poll.h>
#include <stdio.h>
#include <unistd.h>

#define TIMEOUT 5000 //5000ms

int main(int argc, char const *argv[])
{
    struct pollfd fds[1];
    int ret;

    fds[0].fd     = STDIN_FILENO;   //设置文件描述符
    fds[0].events = POLLIN|POLLPRI; //设置读写方式:没有可读事件或者有高优先级数据可读

    ret = poll(fds, 1 , TIMEOUT);
    if(-1 == ret)
    {
        perror("poll");
        return 1;
    }
    else if (0 == ret) //超时
    {
        printf("\n%d seconds elapsed.\n",TIMEOUT);
        return 0;
        /* code */
    }


    char buf[100];
    int len;
    if(fds[0].revents & POLLIN)
    {

        len = read(STDIN_FILENO, buf, 100);
        if(-1 == len)
        {
            perror("read");
            return 1;
        }
        else if (len != 0)
        {
            buf[len] = '\0';
            printf("read:%s\n", buf);
            return 0;
        }
    }

    printf("Noting\n");
    return 0;
}

注:由于本人也是刚接触这个,里面不免会有一些错误,请批判接受。上面只是这两个函数最基本的应用举例,对于更复杂的应用,请自行查阅相关资料。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值