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

来源:互联网 发布:重庆行知小小学校招聘 编辑:程序博客网 时间:2024/05/21 02:35

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 1024int 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 //5000msint 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;}

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

0 0