前言
提示:poll是Linux的
事件轮询机制
函数,每个进程都可以管理一个pollfd
队列,由poll函数
进行事件注册和查询。
1.pollfd结构体
struct pollfd
{
int fd;
short events;
short revents;
}
fd | 文件描述符 |
---|---|
events | 等待发生的事件类型 |
revents | 检测之后返回的事件,当某个文件描述符有变化时,值就不为空 |
2.poll函数
#include <poll.h>
int poll(struct pollfd* fds, nfds_t nfds, int timeout);
fds | 是一个struct pollfd类型的指针,用于存放需要检测其状态的socket描述符 |
---|---|
nfds | 是nfd_t类型的参数,用于标记fds数组中结构体元素的数量 |
timeout | 没有接受事件时等待的事件,单位毫秒,若值为-1,则永远不会超时 |
poll机制会判断fds中的文件是否满足条件,如果休眠时间内条件满足则会唤醒进程;超过休眠时间,条件一直不满足则自动唤醒。
- 返回值>0:fds中准备好读写,或出错状态的那些socket描述符;
- 返回值=0:fds中没有socket描述符需要读写或出错;此时poll超时,时长为timeout;
- 返回值=-1:调用失败。
3.事件标识
常量 | 说明 |
---|---|
POLLIN | 普通或优先级带数据可读 |
POLLRDNORM | 普通数据可读 |
POLLRDBAND | 优先级带数据可读 |
POLLPRI | 高优先级数据可读 |
POLLOUT | 普通数据可写 |
POLLWRNORM | 普通数据可写不会导致阻塞 |
POLLERR | 发生错误 |
POLLHUP | 发生挂起 |
POLLNVAL | 描述字不是一个打开的文件 |
4.实现原理
内核将用户的fds结构体数组
拷贝到内核中。当有事件发生时,再将所有事件都返回到fds结构体数组
中,poll只返回已就绪事件的个数,所以用户要操作就绪事件就要用轮询
的方法。
5.代码案例
和终端交互,在程序运行的时候,在终端输入数据。poll会监听到是否有数据可读,若在timeout时间内有事件发生,则打印出数据;否则,打印poll timeout
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
int main()
{
struct pollfd poll_fd;
poll_fd.fd = 0;
poll_fd.events = POLLIN;
while(1)
{
int ret = poll(&poll_fd, 1, 20000);
if(ret<0)
{
perror("poll");
continue;
}
if(ret==0)
{
printf("poll timeout\n");
continue;
}
if(poll_fd.revents == POLLIN)
{
char buf[1024];
read(0, buf, sizeof(buf)-1);
printf("msg:%s", buf);
}
}
}
运行结果如下:
总结
本文只是简单介绍了一下poll的用法,poll机制监听文件描述符和socket套接字,在进程之间通信时,具有很大的作用。之后我会随着学习的不断深入,继续更新。