liunx io模型多路复用
多路复用
应用程序中同时处理多路输入输出流,若采用阻塞模式,得不到预期的目的;
若采用非阻塞模式,对多个输入进行轮询,但又太浪费CPU时间;
若设置多个进程/线程,分别处理一条数据通路,将新产生进程/线程间的同步与通信问题,使程序变得更加复杂;
比较好的方法是使用I/O多路复用技术。其(select)基本思想是:
1.先构造一张有关描述符的表(最大1024),然后调用一个函数。
2.当这些文件描述符中的一个或多个已准备好进行I/O时函数才返回。
3. 函数返回时告诉进程哪个描述符已就绪,可以进行I/O操作。
select
通过man手册得到函数的用法及参数:
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
功能:
实现IO的多路复用
参数:
nfds:关注的最大的文件描述符+1
readfds:关注的读表
writefds:关注的写表
exceptfds:关注的异常表
timeout:超时的设置
编程步骤:
- 构造一张关于文件描述符的表
- 清空表 FD_ZERO
- 将关心的文件描述符添加到表中 FD_SET
- 调用select函数,监听 select
- 判断到底是哪一个或者是哪些文件描述符发生了事件 FD_ISSET
- 做对应的逻辑处理
通过代码实现:输入鼠标的时候, 响应鼠标事件, 输入键盘的时候, 响应键盘事件 (两路IO)
#include <stdio.h>
#include <sys/select.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[])
{char buf[128] = {0}; // 用于存储读取的数据int fd = open("/dev/input/mouse0", O_RDONLY); // 打开鼠标设备文件if (fd < 0){perror("open err"); // 打开文件出错return -1;}fd_set rfds; // 文件描述符集合while (1){FD_ZERO(&rfds); // 清空文件描述符集合FD_SET(fd, &rfds); // 将鼠标设备的文件描述符加入集合FD_SET(STDIN_FILENO, &rfds); // 将标准输入的文件描述符(键盘)加入集合// 监听文件描述符是否有可读事件int ret = select(fd + 1, &rfds, NULL, NULL, NULL);if (ret < 0){perror("select err"); // select 出错close(fd);return -1;}// 检查标准输入是否有数据可读if (FD_ISSET(STDIN_FILENO, &rfds)){fgets(buf, sizeof(buf), stdin); // 从标准输入读取数据printf("键盘输入: %s\n", buf);}// 检查鼠标设备是否有数据可读if (FD_ISSET(fd, &rfds)){ssize_t n = read(fd, buf, sizeof(buf)); // 从鼠标设备读取数据if (n < 0){perror("read err"); // 读取设备出错}else{printf("鼠标数据: ");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;
}