在上篇文章中提到原作者曾在一天内就凭借 Facebook 的 Wangle 搭建起一个数据库引擎的原型,在这里我会解释我是如何做到的。到本文最后,你将可以用Wangle编写出一个高性能的C++服务器。本文也将作为教程整合进 Wangle 的 ReadMe.md 中。
我将展示如何使用现代C++编写一个Echo服务器,相当于分布式系统开发中的“Hello World”。这个服务器会将接收的消息直接返回。我们同时需要一个可以向我们的服务器发动消息的客户端,在这里可以发现客户端的源码。
Wangle是一个用来搭建事件驱动的现代异步C++服务的C/S应用框架。Wangle最基本的抽象概念就是Pipeline(管线)。能够理解这种抽象,将会很容易写出各种复杂的现代C++服务,另一个重要的概念是Service(服务),其可以看作一种更高级的Pipeline,不过超出了本文我们关注的范畴。
PipeLine
pipeline 是 Wangle 中最重要也是最强大的抽象,可以让用户在定制 request 和 response 的实现时拥有很大的自由。一个pipeline就是一系列request/response控制程序的嵌套。我试图寻找一个真实世界中pipeline的类比,唯一我能想到的就是现实世界工厂中的生产线。一条生产线工作在一种顺序模式下,所有的工人取得一个物体,并且只添加一种修改,再将其发送给上游的工人直到整个产品制造完成。这可能不是一个特别好的比喻,因为流水线上产品的流动是单向的,而一个pipeline能控制反方向的数据流动--就好像将成品分解成原材料。
一个Wangle handler可以同时掌控上游和下游的两个方向的数据流动。当你把所有的handler连接在一起,就可以用一种灵活的方式将原始数据组装为想要的数据类型或者将已有的数据拆分。
在我们的服务器的pipeline中大致将会有下面几种handler:
1.Handler 1 (下文的上游下游是指对一同个handler而言,根据其在pipeline中的位置不同,输入输出相反) 上游:将从socket中接收的二进制数据流写入一个零拷贝(zero-copy,指省略了Applicaion context和Kernel context之间的上下文切换,避免了CPU对Buffer的冗余拷贝,直接在Kernel级别进行数据传输的技术,详情请参阅维基百科)的字节缓存中,发送给handler2
下游:接收一个零拷贝的字节缓存,将其内容写入socket中
2.Handler2 上游:接收handler1的缓存对象,解码为一个string对象传递给handler3 下游:接收handler3的string对象,将其转码为一个零拷贝的字节缓存,发送给handler1
3.Handler3 上游:接收handler2中的string对象,再向下发送至pipeline等待写回客户端。string会发回handler2 下游:接收上游的string对象,传递给handler2
需要注意的一点是,每一个handler应当只做一件事并且只有一件,如果你有一个handler里做了多项任务,比如从二进制流离直接解码出string,那么你需要学会将它拆分。这对提升代码的可维护性和扩展性非常重要。
另外,没错,handler不是线程安全的,所以不要轻易的在其中使用任何没有经过mutex,atomic lock保护的数据,如果你确实需要一个线程安全的环境,Folly提供了一种免于加锁的数据结构, Folly依赖于Wangle,你可以很容易的在项目中引入并使用它。
如果你还不是很明白所有的步骤,不用着急,在看到下面的具体实现时你会更加清楚。
另外,如果有想学习C语言和c++的程序员,可来我们的C语言c++学习扣qun:9416,36044免费送C语言的视频教程噢!我整理了一份适合大学生学习的c++干货,送给每一位想学的小伙伴,并且每天晚上8点还会在群内直播讲解c/c++知识,欢迎大家前来学习哦。