简介

IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:
  (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。
  (2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。
  (3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。
  (4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。
  (5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。
  与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

函数原型

  1. /* According to POSIX.1-2001, POSIX.1-2008 */
  2. #include <sys/select.h>
  3. /* According to earlier standards */
  4. #include <sys/time.h>
  5. #include <sys/types.h>
  6. #include <unistd.h>
  7. /*函数原型*/
  8. int select(int nfds, fd_set *readfds, fd_set *writefds,
  9. fd_set *exceptfds, struct timeval *timeout);
  10. nfds max(fds)
  11. struct timeval *tv;
  12. int select(max(readfds), readfds, NULL,NULL,NULL,tv);

程序实例

循环读取单个文件

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. /* According to POSIX.1-2001, POSIX.1-2008 */
  4. #include <sys/select.h>
  5. /* According to earlier standards */
  6. #include <fcntl.h>
  7. #include <linux/input.h>
  8. #include <sys/stat.h>
  9. #include <sys/time.h>
  10. #include <sys/types.h>
  11. #include <unistd.h>
  12. #define filenamepath "/dev/input/event1"
  13. #define waittimeS (0x20)
  14. int main(int argc, char* argv[]) {
  15. struct timeval tv;
  16. /*数据读取buffer*/
  17. struct input_event inputevent;
  18. fd_set rfds;
  19. /*打开需要读取的文件*/
  20. int ReadFd = open(filenamepath, O_RDWR);
  21. if (ReadFd < 0) {
  22. perror("open");
  23. exit(0);
  24. }
  25. /*must init*/
  26. tv.tv_sec = waittimeS;
  27. tv.tv_usec = 0;
  28. FD_ZERO(&rfds);
  29. /*Set The fds*/
  30. FD_SET(ReadFd, &rfds);
  31. for (;;) {
  32. if (FD_ISSET(ReadFd, &rfds)) {
  33. /*绑定需要读取数据的FD*/
  34. int retval = pselect(ReadFd + 1, &rfds, NULL, NULL,
  35. (const struct timespec* restrict) & tv, NULL);
  36. if (retval < 0) {
  37. /*has error*/
  38. perror("pselect\n");
  39. } else if (retval == 0) {
  40. /*timeout*/
  41. /*超时以后,tv 将会被清零*/
  42. tv.tv_sec = waittimeS;
  43. tv.tv_usec = 0;
  44. printf("timeout");
  45. } else {
  46. /*可以*/
  47. int ret = read(ReadFd, &inputevent, sizeof(inputevent));
  48. printf("inputevent.type %d\n", inputevent.type);
  49. }
  50. } else {
  51. FD_SET(ReadFd, &rfds);
  52. sleep(1);
  53. }
  54. }
  55. (void)close(ReadFd);
  56. }

参考资料

select() - Unix, Linux System Call
linux select函数详解
Linux IO模式及 select、poll、epoll详解