C++网络编程实战项目--Sinetlib网络库(1)——概述

前言

这个网络库是我一直想完成的一个个人项目,到现在也只能说完成了基础的一部分,还有很多功能没完成。因为想往linux c++后台方向发展,所以就打算实现一个网络库,来串联学到的知识,包括APUE、UNP、《Effevtive C++》等等可以说是该方向必看的书籍。暑假的时候我照着陈硕先生的Muduo网络库模仿了一个,学到了很多,但对很多细节不解,所以现在就想重新实现,同时也熟悉整个开发流程。

在这里我将会详细的讲解整个项目的实现,一来是对自己的一个总结,二来也相当于开源出来,以飨读者。当前由于水平所限,可能会有许多谬误之处,望读者多加包涵,并加以指出。

项目地址

如果觉得对你有所帮助,还望能点一下star给我个前进的动力!
silence1772/Sinetlib

简介

Sinetlib是一个仿照Muduo实现的基于Reactor模式的多线程网络库,附有异步日志,要求Linux 2.6以上内核版本。同时内嵌一个简洁HTTP服务器,可实现路由分发及静态资源访问。

  • 底层使用Epoll LT模式实现I/O复用,非阻塞I/O
  • 多线程、定时器依赖于c++11提供的std::thread、std::chrono库
  • Reactor模式,主线程accept请求后,使用Round Robin分发给线程池中线程处理
  • 基于小根堆的定时器管理队列
  • 双缓冲技术实现的异步日志
  • 使用智能指针及RAII机制管理对象生命期
  • 使用状态机解析HTTP请求,支持HTTP长连接
  • HTTP服务器支持URL路由分发及访问静态资源,可实现RESTful架构

开发环境

我使用的系统是Ubuntu 16.04,因为并没有做多平台,只支持Linux,所以如果你使用的是Windows的话,建议你使用虚拟机或者安装双系统,系统版本自然是推荐Ubuntu 16.04,不建议安装最新版的原因是新版可能不太稳定,另外如果你安装的是CentOS等非Debian系的系统的话需要修改构建脚本里面sudo等命令。

因为源码文件有点多,我没有直接用Makefile来编译项目,而是使用CMake。其实CMake只是多了一层抽象,你需要编写CMakeList.txt,然后它会把这个翻译成Makefile文件,最终使用的还是Makefile。

另外,我还使用了持续集成工具Travis CI,它的功能就是当你修改了代码push到github上时,它会根据你写的配置文件自动构建项目,如果构建成功,符合预期,将能够直接部署到服务器上。但是这里我只是想熟悉一下这个工具,并没有使用部署功能,关于如何使用,我也不再赘述,有兴趣的读者可以自行去了解。

编写代码我并没有用IDE,而是使用文本编辑器Sublime Text,这方面看个人习惯吧。

目录结构

├── build.sh................. 工程构建脚本
├── CMakeLists.txt........... CMake规则
├── .travis.yml.............. Travis CI配置文件
├── LICENSE.................. MIT开源协议
├── README.md................ 文档
├── src...................... 源码目录
│   ├── base................. 基础库
│   ├── log.................. 日志库
│   ├── net.................. 网络库
│   └── http................. HTTP服务器
└── example.................. 示例代码

项目的目录结构如上所示,build.sh是整个项目的构建脚本,CMakeLists.txt是CMake的构建规则,源码在src目录中,这里面按照功能分成几个目录,一些示例程序放在example目录下。

编译

首先我们要明确一下编译的目标。我们的项目是一个网络库,既然作为一个库,那么就是要编译成可被其他程序链接的静态库或动态库,另外还需要把example目录下的示例编译成可执行程序。

在Windows下我们一般都是用IDE来开发项目,编译只需轻轻一点,当然Linux下也可以使用IDE,比如Clion,但我一般都是直接写代码,然后使用g++进行编译,比如我们写了一个main.cpp文件,使用了c++11标准,然后要生成可执行程序main,可以使用命令:

g++ -std=c++11 main.cpp -o main

虽然上面只有一条语句,但实际上经过了几个步骤,对于每个.cpp文件,首先要通过预处理把头文件展开出来,然后再通过g++编译成汇编文件.s,接着经过汇编器得到目标文件.o。对于有多个源文件的程序,就是把这多个源文件生成的.o文件链接在一起得到可执行程序。

我们的目标是要得到一个库,那么什么是库呢?其实库就是一组目标文件.o的包,无论静态库还是动态库,都是由.o文件创建的。静态库的后缀名为 .a,动态库为 .so。以静态库为例,我们可以先生成.o文件,再打包生成静态库:

g++ -std=c++11 -c main.cpp
ar cr libmytest.a main.o

现在我们已经知道如何生成库了,但项目里的文件有点多,而且还分了目录,每次编译都要写这么长的命令显然有点力不从心,所以这里就轮到CMake上场了。CMake的语法我就不介绍了,我就讲一下大概的逻辑,可以配合源码来看Sinetlib/CMakeLists.txt

首先我们要设置一下编译选项,比如使用g++编译器,并使用c++11标准,在编译开启所有警告-Wall。另外根据编译类型的不同设置不同的优化级别,可以在build.sh中cmake的语句后加上要编译的类型。

接着我们要设置一下生成文件的目录,这里我设置的是执行cmake命令的目录。然后还需要设置安装的目录,安装的意思就是把生成的库和头文件放到某个目录,要使用时就指定这两个目录即可,我是放在/usr/local/lib和/usr/local/include,这是g++默认的搜索目录,这样我们就可以省去指定目录这一步了。

设置完路径后我们就开始处理源码了,首先遍历所有的源码文件,将它们的文件名保存起来,然后后面直接使用add_library命令生成库,这里还需要使用target_link_libraries命令链接到pthread库,因为我们使用了多线程。这里同时生成了静态和动态库。

最后,我们还需要编译示例程序,在example目录下也有一个CMakeLists.txt,我们只要使用add_subdirectory把example目录包括进来即可。

构建

上面我们已经写好了CMakeLists.txt,接下来就是使用它,这里通过build.sh脚本来构建。

因为生成的文件会在执行cmake命令的目录下,为了不污染原工程的目录,我们首先创建一个build目录,然后进入该目录,因为主CMakeLists.txt在上一级目录,因此我们执行的是cmake ..,这样就会把我们的CMakeLists.txt翻译成可以使用的MakeFile文件了,注意如果要编译Debug版本,可以使用cmake -DCMAKE_BUILD_TYPE=Debug ..,后面加的-D其实就是给cmake传参数,然后我们写的CMakeLists.txt就可以根据这个参数来决定要干什么。

得到MakeFile文件后执行make即可编译,接着执行make install就是把生成的库安装到指定位置。

构建完成后,示例的程序在build/bin目录下,可以直接执行。如果你想修改源码后重新编译,那么不用重新执行build.sh,只需在build目录下执行make即可,当然如果你增加或删除了文件,就需要重新执行了,因为cmake生成的makefile文件只是根据原先的目录情况生成的。

你可能感兴趣的:(网络)