poll函数:
通过man手册查到poll的参数及用法:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
功能: 监视并等待多个文件描述符的属性变化
参数:
1.struct pollfd *fds: 关心的文件描述符数组,大小自己定义
2. nfds: 最大文件描述符个数
3. timeout: 超时检测 (毫秒级):如果-1,阻塞 如果0,不阻塞。
返回值: <0 出错 >0 表示有事件产生;
特点:
- 非阻塞和阻塞模式: 可以在阻塞模式下等待事件发生,或者设置超时时间后返回。
poll
- 适用文件描述符: 可以监视多个文件描述符,包括套接字、文件和设备等。
- 使用结构体: 通过 结构体数组传递文件描述符和事件信息。
pollfd
- 更高效的处理: 适合处理大量文件描述符,相较于 在文件描述符较多时更高效。
select
- 支持事件类型: 可以监听多种事件类型,如可读、可写和异常条件等。
用代码实现:输入键盘事件
#include <stdio.h>
#include <poll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char const *argv[])
{
int ret;
char buf[128] = {0}; // 用于存储读取的数据
int fd = open("/dev/input/mouse0", O_RDONLY); // 打开鼠标设备文件
if (fd < 0)
{
perror("open err"); // 打开文件出错
return -1;
}
// 1. 创建结构体数组
struct pollfd fds[2];
// 2. 配置第一个文件描述符(标准输入)
fds[0].fd = 0; // 文件描述符0代表标准输入(键盘)
fds[0].events = POLLIN; // 关注的事件类型是可读事件
// fds[0].revents=;// 实际发生的事件(会在poll调用后更新)
// 3. 配置第二个文件描述符(鼠标设备)
fds[1].fd = fd;
fds[1].events = POLLIN; // 关注的事件类型是可读事件
// 4. 保存数组内最后一个有效元素的下标
int last = 1;
// 5. 调用poll函数,监听文件描述符事件
while (1)
{
ret = poll(fds, last + 1, 2000); // 2000毫秒超时
if (ret < 0)
{
perror("poll err"); // poll出错
return -1;
}
else if (ret == 0)
{
printf("time out\n"); // 超时无事件发生
}
// 6. 判断文件描述符实际触发的事件
if (fds[0].revents & POLLIN)
{
// 7. 处理标准输入(键盘)事件
fgets(buf, sizeof(buf), stdin); // 从标准输入读取数据
printf("keybroad:%s\n", buf); // 打印键盘输入
}
if (fds[1].revents & POLLIN)
{
// 8. 处理鼠标设备事件
ssize_t n = read(fd, buf, sizeof(buf)); // 从鼠标设备读取数据
if (n > 0)
{
printf("mouse: ");
for (ssize_t i = 0; i < n; ++i)
{
printf("%02x ", (unsigned char)buf[i]); // 打印鼠标数据
}
printf("\n");
}
}
memset(buf, 0, sizeof(buf)); // 清空缓冲区
}
close(fd); // 关闭文件描述符
return 0;
}
,响应键盘事件,输入鼠标事件,响应鼠标事件(两路IO)
思路:
- 打开文件描述符:程序打开了标准输入和一个鼠标设备文件的文件描述符。
- 配置
pollfd
结构体:设置 结构体来关注这些文件描述符上的可读事件。pollfd
- 调用
poll
:在循环中调用 以等待事件发生,设置超时时间为2000毫秒。poll
- 处理事件:根据 字段的值处理标准输入(键盘输入)和鼠标设备的事件。
revents
- 读取和输出数据:从文件描述符读取数据并输出到控制台。
- 清理:循环结束后关闭文件描述符。