1月19日总结
简单来讲I/O多路复用就是用一个进程来监听多个文件描述符(fd),我们将监听的fd通过系统调用注册到内核中,如果有一个或多个fd可读或可写,内核会通知应用程序来对这些fd做读写操作,select、poll、epoll都是用于处理此类问题的系统API,只不过注册和调用的方式略有不同。
例如telnet命令的操作,telnet命令从shell读入数据然后写到socket fd上,同时也需要从socket fd上读数据写到shell上。telnet server需要从socket读出命令并发送给shell,再将命令执行结果返回给telnet客户端。此时对于telnet命令来说,需要接收用户输入和sockfd的输入,也需要输出给用户和socket fd,这两种输入和输出是无序的,不能单纯的阻塞某一个读操作,如何处理这种场景?
将两个read fd设置为非阻塞,然后轮询两个read fd,如果第一个收到数据,则处理,之后再看第二个read fd是否有数据需要读取,如此往复。 使用多进程或者多线程,将用户输入和输出到sockfd作为一条通道。将sockfd输入和输出给用户作为一条通道。
这样父进程读入用户数据后会发送给socketfd到telenetd,子进程读入telnetd数据后发送给用。当用户终止父进程时,需要发送信号给子进程。当子进I/O结束终止时,父进程也需要接收子进程的结束信号。使用多线程同样需要一些复杂的线程间同步操作。
异步I/O的方式,对两个read fd使用不同的信号,使用不同的处理函数处理。
以上三种方法在读写连接少的时候没什么问题,当一个server进程需要维护成千上万条通信连接时就会出问题。第1种会无端浪费cpu,第2种就算使用线程\进程池来避免上下文切换的开销,当连接数量过多的时候,会占用大量的内存,第3种使用异步I/O显然信号类型肯定是不够用的。所以为了应对此类问题,有了I/O多路复用的技术。
使用select、poll、epoll,将两个read fd注册到内核,I/O多路复用会阻塞直到有read请求过来,然后返回通知应用,应用针对不同的描述符进行不同的操作。这样可以做到在一个进程中监听并处理多个描述符,再搭配线程池使用,则可以尽量的减少cpu和内存的使用,自然可以维护更多的连接。
select
本文作者:lmyyyy
本文链接:https://www.cnblogs.com/lmyy/p/17975971
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步