简介
IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:
(1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。
(2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。
(3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。
(4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。
(5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。
与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。
函数原型
/* According to POSIX.1-2001, POSIX.1-2008 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
/*函数原型*/
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
nfds 为 max(fds)
struct timeval *tv;
int select(max(readfds), readfds, NULL,NULL,NULL,tv);
程序实例
循环读取单个文件
#include <stdio.h>
#include <stdlib.h>
/* According to POSIX.1-2001, POSIX.1-2008 */
#include <sys/select.h>
/* According to earlier standards */
#include <fcntl.h>
#include <linux/input.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define filenamepath "/dev/input/event1"
#define waittimeS (0x20)
int main(int argc, char* argv[]) {
struct timeval tv;
/*数据读取buffer*/
struct input_event inputevent;
fd_set rfds;
/*打开需要读取的文件*/
int ReadFd = open(filenamepath, O_RDWR);
if (ReadFd < 0) {
perror("open");
exit(0);
}
/*must init*/
tv.tv_sec = waittimeS;
tv.tv_usec = 0;
FD_ZERO(&rfds);
/*Set The fds*/
FD_SET(ReadFd, &rfds);
for (;;) {
if (FD_ISSET(ReadFd, &rfds)) {
/*绑定需要读取数据的FD*/
int retval = pselect(ReadFd + 1, &rfds, NULL, NULL,
(const struct timespec* restrict) & tv, NULL);
if (retval < 0) {
/*has error*/
perror("pselect\n");
} else if (retval == 0) {
/*timeout*/
/*超时以后,tv 将会被清零*/
tv.tv_sec = waittimeS;
tv.tv_usec = 0;
printf("timeout");
} else {
/*可以*/
int ret = read(ReadFd, &inputevent, sizeof(inputevent));
printf("inputevent.type %d\n", inputevent.type);
}
} else {
FD_SET(ReadFd, &rfds);
sleep(1);
}
}
(void)close(ReadFd);
}
参考资料
select() - Unix, Linux System Call
linux select函数详解
Linux IO模式及 select、poll、epoll详解