1.3 实践项目——锦上添花
众所周知,程序设计不能仅靠学习理论知识,打下一定基础后,针对业界知名的消息中间件或开源项目进一步学习和实践。有过实习经历的同学已经积累了较为出色的实践经验。但对于没有实习经历或项目经验的同学来说,通常在课程中完成的课后大作业或者参与的科研项目似乎并没有太大的应用价值,对自身的能力提高也有限。因此,一两个优秀的且与求职方向匹配的实践项目能够为简历锦上添花。
1.3.1 C++网络编程(动手编写server)
造个后台的轮子不仅能够将所学的基础知识有效运用,而且能够将掌握到的语言基础、数据结构、操作系统、计算机网络、数据库等知识得到有效结合。这项实践对于程序设计的能力、server的架构设计均有理解和提升。C++网络编程是利用Linux C++提供的socket api达到不同主机的进程间通信目的,需要程序员首先具有C++程序设计的基础,且对计算机网络协议栈有一定的认知。当server编写并持续运行后,可以继续投入精力到架构设计中,例如:服务状态和数据落地(存储MySQL、Redis)、server入口设计负载均衡agent、使用etcd监控server活性等等。对于后台开发程序员来说,网络编程是相对基础的能力,应该掌握以下要点:
- socket套接字的概念
- Linux-C++ socket api的函数使用方法与流程
- socket api函数与对应的网络协议栈状态关联关系
- I/O复用模型:select、epoll
- 网络粘包、少包如何解决
- 如何设计Reactor模型
- 多线程编程:互斥、条件变量、异步、线程池等
- C++内存管理:内存池、对象池
当网络通信引擎搭建好后,可以继续扩展server提供的服务能力,例如提供HTTP报文的处理能力、搭建成聊天室、电商、支付等系统。
推荐阅读的书籍有《Linux高性能服务器编程》、《Linux多线程服务器端编程》。相信大多同学们共有的问题或疑惑是,我目前已经有程序设计、操作系统、计算机网络基础了,但是还是不知道如何着手进行实践。我认为,同学们缺少项目实践由浅入深的过程。应该首要明确server开发是做什么(需求分析),接着再针对需求理清需求方案(这里可以用到UML的建模方法),最后再按照方案进行编程实现。在本专栏中会对C++网络编程进行基础介绍,接着用两片文章讲解简易的网络通信引擎开发与Reactor工作模型。
1.3.2 知名开源项目
业界知名开源项目的架构和源码具有很高的学习价值,例如redis、nginx,关于这类项目的文章和视频介绍也较多,非常适合拿来学习和仿作。
(1)拿redis举例,仿照着教学文章/视频搭建起redis进行简单的KV存储/修改/持久化等操作是相对容易的,但后台开发程序员不能局限于消息中间件如何使用,而应该深入学习redis的数据结构、线程/进程架构、网络通信引擎、内存优化方式等。了解了这些后,再付诸实践去仿作一个KV存储引擎。
(2)此外还有一些Github上开源的项目,有的聚焦于某一个库的实现,这类项目代码量一般较少,可读性较高(下表1-4);还有的项目是仿造的后台轮子,这类项目则结合了后台开发的多类内容,是比较综合且学习价值高的项目(下表5)。
- 1.实现JSON库,一个跨平台、C风格的JSON库;在项目中可以学习到高效、优雅的C代码,还能了解到有关单元测试的技巧。
- 2.实现STL库,STL标准库是C++程序员必须掌握的基础知识,该项目仿写了大部分STL容器、迭代器、算法。候选人可以仿照该项目,自己再实现部分有关STL标准库的内容,使自己对STL的掌握更牢固。
- 3.实现线程池,线程启动与回收都是对系统资源的消耗,线程池对线程资源进行高效管理,是后台常驻server进行并发编程的必要手段,该项目结合C++11的thread线程库实现了简洁、高效的线程池,其源码值得阅读并复用。
- 4.MySQL连接池,与线程池类似的,MySQL连接池同样是server接入MySQL数据库的高效管理方式;该项目是基于C++实现的MySQL连接池,其源码值得阅读并复用。
- 5.WebServer,该项目为基于C++11编写的Web服务器,是对程序设计基础、数据结构、操作系统、计算机网络等知识的综合运用;在候选人具备一定基础后,非常有必要对该项目进行学习和剖析。
总的来说,阅读较为精简的库和较为综合的项目源码都能提升自身的代码阅读能力和程序设计能力,阅读一个库源码主要是学习数据结构的设计、标准库的妙用、异常的捕获与处理等这类C++程序设计的技巧。但综合性项目对于学习者来说学习性更强,更适合综合提升后台开发的能力。以项目5-WebServer为例,相信大多候选人往往具有一个疑问:这个git仓库我clone了以后,看了源代码觉得写的挺好的,但是我不知道如何入手,不知道应该做什么。我想根据自身的经验,给同学们一些建议:
- 1.首先明确学习的目的:学习该项目的进程线程模型、网络通信与I/O处理模型、内存优化方法,此外包括业务处理逻辑、日志系统设计、甚至引入其他中间件架构模型。
- 2.在有了该项目的总体设计思路后,思考如何入手。例如该项目是一个多线程工作的web server服务器,主线程用于接受客户端的连接,并将工作任务分配给其他工作线程处理;使用线程池避免频繁创建和销毁带来的开销。有了这个思路,我们可以模仿去编写一份自己的web server:(1)首先不考虑多线程,在主线程中接受客户端连接和消息处理,即先把网络通信引擎搭建起来;(2)接着再编写一个线程池类,用于执行普适性的线程任务工作。(3)再把主线程进行改造,支持多线程处理客户端的请求。
- 3.上述三个步骤可以继续细分,例如网络通信引擎先按步骤搭建创建socket、监听端口、调用accept和recv接受请求和数据;再引入I/O复用是其能对多个客户端的请求进行较好的支持。这需要同学们具备相应的网络编程基础,同理多线程的改造需要同学们具有并发编程的基础。所以在进行项目实践前,大家还是要认真夯实基础,这样在面对复杂的项目代码时才能灵活思考。