项目后端使用C++开发语言,以Linux为开发环境,基于epoll边缘非阻塞模型,从http协议的解析,到表单multipart/form-data协议的解析,再到JSON协议的解析,再到C++对象的序列化,一步一个脚印实现一个http服务器。实现的功能有文件的上传、下载、删除、改名等。
前端采用vue框架,为了简单,没有使用node.js,使用httpVueLoader来解析vue文件,因为前端不是重点。
- centos 7
- gcc version 7.3.1
- cmake 3.17
为了方便线程的管理已经线程资源的释放,所有的线程[除了主线程]都从线程池中获取
网络模块:
- acceptor 单独一条线程[本项目中是在主线程中],负责监听客户端的连接
- poller 单独一条线程,负责监控客户端的读写事件
- executor 线程池,负责处理客户端的请求,每个请求一条线程,读取请求数据,解析请求数据,做业务,发生响应数据都在该条线程中
日志模块:
- logger 开启异步日志后,日志模块单独一条线程
因网络包发生和接受的不确定性,本项目采用状态机去解析http协议
- 日志管理,模仿log4j的实现逻辑,支持异步日志
- Json解析/Json序列化,C++对象的Json序列化 支持递归结构
- Http协议解析;支持表单格式解析;支持状态保存
- 线程池,可拓展,模仿QT QThreadPool线程池的实现,同时拓展了核心线程
- 模仿springmvc风格的controller
- 一些其他的工具和封装
- vue
- element-ui组件库
- httpVueLoader的使用,本项目前端只是辅助展示,所以并没有安装node.js,直接用httpVueLoader来解析vue文件
启动参数如下
[root@localhost tmp.mkWXUL9TBY]# ./candy -h
-a --addr 监听地址
-d --daemon 后台运行
-f --file 配置文件
-h --help 帮助
-p --port 端口
-s --stop 停止服务器
启动
[root@localhost tmp.mkWXUL9TBY]# ./candy -p8888
2021-03-22 23:47:36.950 INFO candy[139832041047872] poller.cpp:25 Poller >> epoll create success!!
2021-03-22 23:47:36.951 TRACE candy[139832041047872] acceptor.cpp:56 acceptAt >>
████████ ████ ████ ██ ███████ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ████████ ██ ██ ██ ██ ██ ██████
██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██
████████ ██ ██ ██ ████ ████████ ██ run at http://0.0.0.0:8888
然后浏览器便可以访问了
写一个HomeController.cpp文件,添加相对应的路径和方法映射,便能生成接口。支持Json对象,网页,以及直接返回。具体写法参照路径/src/app/controller下的controller的写法
#include "../../container/controller.h"
#include "../../log/logger.h"
#include "../../util/urlutil.h"
struct HelloWorld {
int code = 10;
std::string msg = "hello-world";
std::vector<int> ids = {1, 9, 2, 3, 4, 5};
std::vector<HelloWorld> hello3;
};
//序列化
Serialization(HelloWorld, code, msg, ids, hello3)
//添加一个控制器
struct HomeController : public Controller<HomeController> {
//返回的是网页路径
RequestMapping(home, "/")
std::string home(HttpRequest *request, HttpResponse *response) {
return "/index.html";
}
//返回的是Json对象
RequestMapping(hello, "/hello")
ResponseBody hello(HttpRequest *request, HttpResponse *response) {
HelloWorld helloWorld;
helloWorld.hello3.emplace_back();
return helloWorld;
}
//直接写到responseBody中
RequestMapping(hello2, "/hello2")
void hello2(HttpRequest *request, HttpResponse *response) {
//直接输出......
response->getBody().append("123");
}
};
- 如果遇到服务器启动了,但是却无法访问的情况,请检查是不是所选的端口开放了访问