I/O多路复用-poll的详解

既然已经有select实现IO多路转接了,为什么还要有poll?
之前说过select有很多的缺点:
在这里插入图片描述
而poll的出现解决了select的两个问题:
1、可监控的文件描述符个数有上限
2、参数即作为输入参数又做输出

poll函数的声明:

int poll(struct pollfd* fds, nfds_t nfds, int timeout)

参数解释:
1、fds:监听结构列表,包含三部分内容(文件描述符,监听的事件集合,返回的事件集合)
struct pollfd结构:
I/O多路复用-poll的详解_第1张图片
events和recvents的取值,这里仅介绍可读和可写:
数据可读:POLLIN
数据可写:POLLOUT
2、fds数组长度
3、timeout:等待时间,单位是毫秒
在这里插入图片描述
所以poll的使用,一般是先定义一个struct pollfd类型的数组,假设要监视0号文件描述符的读事件,就把数组的第一个元素的fd设为0,events设为POLLIN,而revents为返回,当数组的第一个元素的revents变为POLLIN,表示0号文件描述符的读事件就绪。

返回值解释:
大于0:监听的文件描述符就绪,poll返回
等于0:超时返回
小于0:出错

socket就绪条件

  • 读就绪

sochet内核中,接收缓冲区中的字节数,大于等于低水位标记SO_RECVLOWAT,此时可以无阻塞的读该文件描述符,并且返回值大于0
socket TCP通信中,对端关闭连接,此时对该socket读,则返回0
监听的socket上有新的连接请求时
socket上有未处理的错误时

  • 写就绪

socket内核中,发送缓冲区中的可用字节数(发送缓冲区的空闲位置大小),大于等于低水位标记,SO_SNDLOWAT,此时可以无阻塞的写,并且返回值大于0
socket的写操作被关闭(close或者shutdown),对于一个写操作被关闭的socket进行写操作,会触发SIGPIPE信号
socket使用非阻塞connect连接成功或失败之后
socket上有未读取的错误

  • 异常就绪

socket上收到带外数据(关于带外数据,和TCP紧急模式相关,在TCP报头中有一个紧急指针的字段)

编写poll代码:
一、检测标准输入

  1	#include
  2 #include
  3 #include
  4
  5 int main(){
  6     // 因为只关心一个文件描述符,所以就不定义数组了,第二个参数填1就好
  7     // 关心0号文件描述符(标准输入)的读事件
  8     struct pollfd poll_fd;
  9     poll_fd.fd = 0; // 标准输入
 10     poll_fd.events = POLLIN; // 读事件
 11     // poll_fd.revents为输出型,返回事件的集合
 12     while(1){
 13         int ret = poll(&poll_fd,1,3000); // 数组大小为1,等待时间为3000ms(3秒)
 14         if(ret < 0){
 15             printf("poll error\n");
 16             continue;
 17         }
 18         if(ret == 0){
 19             printf("poll timeout\n");
 20             continue;
 21         }
 22         if(poll_fd.revents == POLLIN){// 当0的读事件就绪时
 23             char buf[1024] = {0};
 24             read(0,buf,sizeof(buf)-1);
 25             printf("input:%s\n", buf);
 26         }
 27     }
 28     return 0;
 29 }

运行效果为超过3秒不往标准输入写数据,poll会立刻超时返回,如果想标准输入写数据,则标准输入的读会就绪,然后把数据回显.
I/O多路复用-poll的详解_第2张图片

二、模拟实现poll服务器

//初始化监控列表数组,把fd设为-1,监听和返回事件设为0
void Initpolled(struct pollfd* fd_list,int size)
{
    int i = 0;
    for(i = 0; i: $s\n",buf);
            }
        }
    }
    return 0;
}

客户端和select相同。
poll的优点:
不同于select使用三个位图来表示三个fdset的方式,poll使用一个pollfd的指针实现

1、pollfd结构包含了要监视的enent和发生的event,不再使用select“参数-值”传递的方式,接口使用比select更加方便
2、poll并没有最大数量限制(但是数量过大后性能也是会下降)

poll的缺点
poll中监听的文件描述符增多时:

1、和select一样,poll返回后,需要轮询pollfd来获取就绪的文件描述符
2、每次调用poll函数都需要把大量的pollfd结构从用户态拷贝到内核中
3、同时连接的大量客户端在同一时刻可能只有很少的处于就绪状态,因此随着监视的文件描述符数量的增长,其效率也会线性下降

1、poll返回后也需要轮询fd_list列表来获取就绪的文件描述符
2、需要把polled从用户态拷贝至内核态
3、虽然没有数量限制,但是数量过大,性能也会线性下降

你可能感兴趣的:(I/O多路复用-poll的详解)