c++网络库发展

C++也可以做到非常快速的开发。有句俗语 * “脚本一时爽,重构火葬场” * 说的正是脚本语言开发的项目进入维护阶段后无穷的灾难。

C++11 开始,已经 感觉像是全新的语言了,可以完全以脚本的形式去使用。

(1)select-> epoll kqueue

UNIX提供了 select() 系统调用供人驱使.然而只能支持 1024 个文件描述符, windows 上的 select 更是只能使用64个.

IBM 搞了 IOCP . BSD 发明了 Kqueue. Linux 捣鼓出了 epoll.

《Pattern-Oriented Software Architecture》ACE 犯了早期 C++ 库都会犯的一个错误,过度设计, 过度java化。所谓 java 化, 就是以对象代替接口, 以虚函数代替回调,以继承代替组合。以虚类代替模板。对象间关系错综复杂,牵一发而动全身。

 

(2) C语言的复辟,带来了几个更为糟糕的替代品, libevent 和 libev,以及 乘着nodejs的盛行东风而来的 libuv。

 

a 简陋原始的 libevent . 从 OS 那里获得事件, 然后派发。派发机制就是“回调函数”。异步,归根结底就是处理从操作系统获得的事件。iocp epoll 都只是用来获取事件的接口。libevent 去掉了ACE华而不实的包装,保留了异步事件,极大的简化了模型。

 

b 禁锢的 libev

libev吸收了 libevent 的所有缺点,
向下改进还不如直接使用系统的 api, 向上改进,很快就碰到了 C 语言强加的禁锢。

编写异步程序, 最需要的2个抽象能力, 其一为协程,其二是函数对象,包括匿名函数对象, 也就是lambda。
函数对象是实现闭包比不可少的,如果没有函数对象, 就只能通过携带 void* 指针的形式迂回完整,繁琐不说,还特别容易出错。程序里也到处充满了类型强转。到处是临时定义的类型,就为了传给 void*使用。

 

c libuv 就出来给 libev 擦屁股了。 C 语言的异步库所能达到的最高高度了。完完全全的触碰到了C语言的自身瓶颈,好在 libuv 只是 nodejs 的底层库,上层软件转移到 javascript 语言而逃避了 C 的禁锢。

网络出错的情况下, libuv 的用户只能稀里糊涂的知道出错

 

 

(3)ASIO  
网络库不宜做成框架,而是要像系统的API那样,ACE 做成了一个框架,同样不妥。

ASIO 终于在 2017 年进入了 c++ 标准。

为什么 Proactor 会是最佳模型?
  • 跨平台 许多操作系统都有异步API,即便是没有异步API的Linux, 通过 epoll 也能模拟 Proactor 模式。
  • 支持回调函数组合 将一系列异步操作进行组合,封装成对外的一个异步调用。这个只有Proactor能做到,Reactor 做不到。意味着如果asio使用Reactor模式,就对不起他“库” 之名。
  • 相比 Reactor 可以实现 Zero-copy
  • 和线程解耦 长时间执行的过程总是有系统异步完成,应用程序无需为此开启线程

Proactor 也并非全无缺点,缺点就是内存占用比 Reactor 大。Proactor 需要先分配内存而后处理IO, 而 Reactor 是先等待 IO 而后分配内存。相对的Proactor却获得了Zero-copy好处。因为内存已经分配好了,因此操作系统可以将接受到的网络数据直接从网络接口拷贝到应用程序内存,而无需经过内核中转。
Proactor 模式需要一个 loop ,这个 loop asio 将其封装为 io_service.他不仅是 asio的核心,更是一切基于asio设计的程序的核心。

宇宙级异步核心

io_service 脱胎于 IO 但不仅用于 IO. Christopher Kohlhoff 在给委员会的另一份编号 N3747 的信上上说它是 ~~宇宙级异步模型~~ Universal Asynchronous Model。在宇宙级异步模型里,一个异步操作由三部分构成

  1. 发起 按照 asio 的编码规范,所有的发起操作都使用 async_ 前缀,使用 async_动词 的形式作为函数名。
  2. 执行 异步过程在发起的时候被executor执行(系统可以是支持 AIO 的内核,不支持 AIO 的系统则是 aiso 用户层模拟)
  3. 完成并回调 在发起 async_* 操作的时候,总是携带一个回调的闭包。asio使用闭包作为异步事件完成的处理回调,没而不是C式的回调函数。asio的宇宙异步模型里,回调总是在执行 io_service::run 的线程里执行。asio绝不会在内部线程里调用回调。

在回调里发起新的异步操作,一轮套一轮。整个程序就围绕着 io_service::run 运转起来了。
io_service 不仅仅能用于异步 IO ,还可以用来投递任意闭包。实现作为线程池的功能。这一通用型异步模型彻底击败微软 PPL 提案,致使微软转而研究协程。然而微软在协程上同样面临 asio 的绞杀。

闭包和协程

宇宙级 asio 使用闭包作为回调,而 C 库只能使用函数+void*, ACE 虽然使用的 C++语言,却不知道闭包为何物,使用的是 虚函数作为回调。需要大量的从 ACE 的对象继承。以闭包为回调,asio更是支持了一种叫“无栈协程”的强悍武器。
asio的无栈协程,仅仅通过库的形式,不论是在性能上,还是易用性上,还是简洁性上,甚至是B格上,都超过了微软易于修改语言而得的 await提案。

微软,乃至 ACE ,并不是不知道闭包,而是在c++里实现闭包的宇宙级executor —— 也就是 io_service,需要对模板技术的精通。
asio 以地球人无法理解的方式硬是在 c++98 上实现了宇宙级异步核心。

buffers

有了闭包的支持,内存管理也变得轻轻松松起来。
ASIO 本身并不管理内存,所有的IO操作,只提交对用户管理的内存的引用,称 Buffers。asio::buffers 引用了用户提交的内存,保持整个 IO 期间,这块内存的有效性是用户的责任。然而这并不难!
因为回调是一个闭包。通过闭包持有内存,只要 asio 还未回调,闭包就在,闭包在,内存在。asio 在调用完回调后才删除相应的闭包。因此资源管理的责任可以丢给闭包,而闭包可以通过智能指针精确的控制内存。
不是 GC , 胜于 GC 千百倍!益于c++的 RAII机制,再无内存泄漏之忧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值