自学内容网 自学内容网

c++应用网络编程之四Linux常用的网络IO模型

一、网络IO模型的实际应用

在前面学习了基本的网络IO模型,那么这种抽象的网络IO模型如何在实际的编程中应用呢?这其实就是理论与实际如何产生联系的一个过程。在现实世界中,有了理论的指导,下一步就是要把相关的理论如何与具体的实践相结合。一个真正的学习者,恰恰是一个好的应用者。从抽象到实践其实是有一些规律可以遵循的。最基础的办法就是使用一些现有的实践模型,将其在场景中应用并不断的掌握其中的内在情况,不断的适应和修改二者的平衡点。即使最终没有成功的把某种模型与实际场景结合成功,那么也明白了这种场景与这种模型的不匹配的所存,这就是迈向实践过程的第一步。
在Linux的网络IO模型中,常用的也就几种,下面就其进行一下分析和说明。

二、Linux平台下的常用IO模型

这里的Linux其实指是常见的大多数的类Linux平台。在这些平台上,常用的IO网络模型其实主要有以下几个:
1、BIO,同步模型
这种模型,就是最原始的模型。即直接使用网络套接字,按照套接字的流程进行编程。这种编程方式,简单、方便。对于处理一些常见的基础的网络通信,特别是一对一的网络命令通信时,就相当有效。而它的基本应用场景就是,客户端和服务端是单映射,通信数据量较小,通信环境一般是自组网或局域网内。
这种模型非常简单,就不再深入分析了。

2、select IO多路复用模型
在Linux中提供了函数:

int select(int nfds, fd_set *r, fd_set *w, fd_set *e, struct timeval *timeout);

这种模型就是为了解决同步IO的问题,它解决了服务端1:N的问题。即每个服务端可以连接多个客户端而不需要单独的创建线程来控制。select模型的本质其实就是内核处理一个遍历文件描述符数组(fd,网络通信句柄)可读写(就绪)的过程。它适应的场景一般是并发不太高的情况下,而且由于是遍历,所以效率不高。通常select模型默认的扫描数量是1024(32位)或2048(64位)。当然,此数量可以在头文件中自行修改,不过不建议这么做。
其由POSIX定义,所以基本各个平台都会有支持。

3、poll IO多路复用模型

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

这个模型的本质和select模型没有本质区别,都是遍历文件描述数组的过程。只不过在这个模型中采用了链表方式保存文件描述符,故基本上可以理解为没有了select模型中的限制。它的适应场景和select基本一样,虽然从理论上可以用于更高的网络并发,但其实带来的编程复杂度,使其得不偿失。但在一些特定的场景下,如并发很多,但实际活动连接不多的情况下,它还是有用武之地的。
4、epoll IO多路复用模型
epoll比较复杂,它由一组函数epoll_create,epoll_wait,epoll_event 和epoll_ctl等相关操作组成。epoll分为两种触发方式,即LT,Level-Triggered(水平触发)和ET,Edge-Triggered(边缘触发)。LT一般来说适用比较广,常见的epoll编程基本以这种居多,最适合高并发场景,因为虽然叫高并发,但具体到某一个时刻,真正处于活动的则未必非常多。而ET一般适用于处理事件触发这个动作会引起的后果的场景,由于其只动作一次,所以能更好的提高通信效率。它更适合于大数据量的通信。
上面的详细应用细节,会在后面分章节逐一进行分析和应用说明。除此之外,还有其它一些平台比如Solaris的evport,Free BSD中的Kqueue(MacOS),但均不是常用的,这里都不再介绍,有兴趣的可以自己分析一下,其实原理都基本类似。
另外在前面单独分析过最新的IO模型IO_URING模型,这里就不再重复,有兴趣的可以翻看以前的文章“Linux新的IO模型io_uring”。
最后,需要说明的是,这三种IO模型本质上仍然是同步IO,特别是epoll很多人容易将其理解成异步IO,一定要记清楚,它也是同步IO。这也是大多数人都知道的Windows上的IOCP模型要比其效率更高的原因。

三、比较分析

理论上讲select和poll模型基本算是一个水平,它们需要在内核空间和用户空间进行文件描述符的复制,这意味着两种状态空间的切换,代价肯定是大的。所以其不适合于高并发的场景。同时,poll还是一种反复触发机制,即如果发现fd就绪后未处理,则会再次扫描时继续触发。而epoll则是共享内存空间不需要在两种状态空间间进行数据的拷贝交换。
select模型的有处理文件描述符的上限,一般不建议修改;poll虽然没有上限,但处理大量文件句柄时会带来效率的快速降低。而epoll则通过事件触发机制进行回调处理,所以对上限基本不敏感。但如果活跃连接过多导致事件触发频繁,仍然会可能导致性能和效率的问题。在一般情况下epoll可以轻松处理c100k的问题。如果机制的配置升高,则还可以进一步的提高。不过需要注意的是,网络的高并发和高并发处理是两个问题,这个经常被很多人忽视。举一个简单例子即可明白,一个服务端连接了十万个客户端,但只有极少的客户端是活跃的;另外一个服务端连接了十万个客户端但基本都是活跃的。
从开发者普遍的意识上来看,可能epoll的效率最高。但其实则未必,这要看应用场景,比如在连接少(十的量级),但活跃并发高(十个全部在通信且数据量相对较多)时,select和poll模型很有可能比epoll模型效率更高。
大家一定要记住,所以效率一定是相对的而不是绝对的,适合的才是最好的。

四、总结

实事求是,与时俱进,理论联系实际,实践是检验真理的唯一标准…,这些理论每个人可能都会脱口而出。但真正的应用环节呢?可能绝大多数人会有意无意的找各种借口,陈陈相因,因循守旧,更别提创新意识了。只有在实践中深入分析掌握了现有技术的优劣,才可能知晓应用场景下的各种技术不足,才可能产生创新意识。网络编程中这种例子特别多(如io_uring,dpdk),毕竟实际应用的在不断提高对网络技术的要求。而更可怕的是,这种要求不但没有降低还在不断的提高。
网络编程技术是一个计算机编程技术的集大成的方向,是一个软件开发者攀登的高峰。愿与诸君共勉,一同登峰赏景!


原文地址:https://blog.csdn.net/fpcc/article/details/140567476

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!