I/O多路复用
在UNIX/Linux下主要有4种I/O模型:
阻塞I/O:
- 最常用
- 同步通信模型
- 阻塞I/O模式是最普遍使用的I/O模式,大部分程序使用的都是阻
塞模式的I/O。 - 缺省情況下,套接字建立后所处于的模式就是阻塞1/0模式。
- 前面学习的很多读写函数在调用过程中会发生阻塞。
-读操作中的read、recv、 recvfrom
-写操作中的write、send,(sendto不阻塞)
-其他操作: accept、connect - 阻塞I/O会导致调用该函数的进程或线程会被阻塞,不会被内核进行调度
- 处理不当会造成进程、线程被永远阻塞
以read函数为例:
- 进程调用read函数从套接字上读取数据,当套接字的接收缓冲区中还没有
数据可读,函数read将发生阻塞。
它会一直阻塞下去,等待套接字的接收缓冲区中有数据可读。- 经过一段时间后,缓冲区内接收到数据,于是内核便去唤醒该进程,通过
read访问这些数据。- 如果在进程阻塞过程中,对方发生故障,那这个进程将永远阻塞下去。
非阻塞I/O:
- 可防止进程阻塞在I/O操作上,需要轮询
- 同步通信模型
- 当我们将一个套接字设置为非阻塞模式,我们相当于告诉了系统内核: 当我请
求的1/0操作不能够马上完成,你想让我的进程进行休眠等待的时候,不要这么
做,请马上返回一个错误给我。 - 当一个应用程序使用了非阻塞模式的套接字,它需要使用一个循环来不停地测试
是否一个文件描述符有数据可读(称做polling )。 - 应用程序不停的polling内核来检查是否1/0操作已经就绪。这将是一个极浪费
CPU资源的操作。 - 这种模式使用中不普遍。
非阻塞I/O模式就和普通的全局变量、普通的缓冲区没有什么区别,需要不停的查询,缓冲区没有数据的时候cpu也要去运行查询的操作,极其浪费cpu资源。
信号(事件)驱动I/O:
- 一种异步通信模型
I/O多路复用:
- 允许同时对多个I/O进行控制
- 同步通信模型
IO多路复用的原理:当一个进程中有多个需要阻塞的文件描述符同时运行的时候,就把需要阻塞的这些文件描述符加到一个集合里面,当一个或多个阻塞的函数有数据到来是就返回集合阻塞函数,然后再查询具体是哪个阻塞文件描述符有数据到来了,处理完数据后继续集合阻塞。
- 基本常识:
linux中每个进程默认情况下,最多可以打开1024个文件,最多有1024个文件描述
符
文件描述符的特点:
1.非负整数
2.从最小可用的数字来分配
3.每个进程启动时默认打开0, 1,2三个文件描述符
多路复用针对不止套接字fd,也针对普通的文件描述fd
linux的文件描述符集合图示:

IO多路复用就是围绕着fd_set这个结构体做操作
IO多路复用相关函数:
1 | void FD_ZERO(fd_set *fdset); // 对集合清零 |
注:select()退出后,集合表示的是有数据的集合,有数据的集合是原来传入集合的子集。
通过 if (FD_ISSET(fd, fdset)) 判断,fd是否在这个有数据的集合中。
如果fd是监听套接字:有新的客户端连接。
如果fd是已连接客户端的套接字:客户端有数据过来。

示例程序:
服务端
1 | //伪代码: |
客户端:
1 |
|
运行结果:

1.文件描述符集合:把多个需要阻塞等待的文件描述符假如到一个数组当中,当有其中一个或多个文件描述符有数据可读时,进程会被唤醒运行,然后找出是哪个文件描述符再处理这个文件描述符的数据。
2.文件描述符集合不光只对网络编程可用,对所有的文件io都可以用。
3.文件描述符使进程中多个需要阻塞的地方变成一个地方阻塞,解决了以往进程中有多个阻塞等待文件描述符数据的时候需要开多个进程或线程的问题。
源码地址:http://gitea.880755.xyz/private/TCP_IO_Demo.git
- 本文作者: 龙兄嵌入式
- 本文链接: https://hexo.880755.xyz/1970/01/01/zblog/download/60. IO多路复用网络编程(终极篇)/