基于mongoose的轻量级webserver
这篇文章的起因只有一个那就是在之前的一个项目之中我们准备做一套轻量级的三维可视化项目。但是这个项目如果按照常规的ue4或者unity之内的引擎来做的话直接面临的问题就是太大了。一般来讲一个在windows上面运行的ue4项目少说就是一个G。效果固然漂亮但是代价很大。
为了在减少打包的文件量的同事也完成对应的功能我们就将目光放到了webgl上面,这个东西是无需封装的一套现有框架而且比起UE4之内的桌面级引擎其实更加容易上手。最重要的是最终的封装项目在压缩之后其实是非常轻量级的而且可以跨平台部署。但是为了实现对web内容的窗口化所以项目要求最终的封装需要时一个桌面级程序。大致想了一下如果我们直接使用QT进行桌面程序的编辑同时用QWebEngine来进行对页面的展示与窗口化岂不是完美?
这就是项目的思路但是开始了没多久便发现了一个重要的问题,那就是无论是three.js还是babylon.js在使用QT的webengine时都无法使用qrc模式进行对页面文件的加载,使用qml由异常的SB,如果部署一台线上的服务器为了达到模型的带宽要求价格又很高所以我便开始思考有没有一个成熟的轻量级的webserver库可以直接拿来用的?最终找到了一个神奇的东西那就是mongoose。一般来讲实现一个webserver最直接的方法就是使用boost库,但是这个东西号称比std都还要伤,我便放弃使用了,于是再开始想有没有其他的东西可以满足我的要求,这个mongoose优势便体现出来了,最重要的就是他就一个.c文件和一个头文件便完成了所有的工作可以实现对一个文件夹http穿透,可以实现对请求的拦截、参数的获取、响应的处理。说白了要是自己有一定的封装基础与后端开发经验,这个东西完成可以实现一个复杂的web后端开发。缺点也不是没有那就是她是C编写的,整个库就是一个流程化的东西没有什么对象可以使用,所以尝试使用这个东西还需要自己进行封装不然实际生产过程写起来就很伤了。
我使用msvc编写一个简单的封装目的也十分的单纯仅仅是为了实现对一个本地文件夹的http服务器的搭建。最终运行与QT之中并且编译为库之后完美运行简直不要太完美,最终项目实现的结果非常不错无论是加载速度、响应时间、兼容情况都是非常可观的。不废话了我现在就将基础部分的封装的类拿出来,上代码!
头文件http_sercer.h
#pragma once #include <string> #include <unordered_map> #include <functional> //在C++之中添加C支持,这个是为了预编译头的问题 extern "C" { #include "mongoose.h" } //静态的server配置项,这个东西必须与对象无关,因为在回调里面会使用 static struct mg_serve_http_opts s_http_server_opts; class HttpServer { public: //默认构造 HttpServer(); //初始化,使用端口与对应的web映射路径(windows的绝对路径或者相对路径都可以) void Init(const std::string &port, const std::string &path); // 启动httpserver bool Start(); // 关闭httpserver bool Close(); private: //连接管理器 struct mg_mgr mgr; //连接的对象(这个东西是一次声明,多次连接是不同的实例就是这个结构体) struct mg_connection *nc; //端口号 const char *s_http_port; //这个是回调函数,每当一个连接来的时候进行回调,只能是静态函数因为绑定连接的时候必须传入函数指针 static void ev_handler(struct mg_connection *nc, int ev, void *p); };
源文件http_server.cpp
#include "http_server.h" //默认构造 HttpServer::HttpServer(){} //对应连接到来时的回调函数,这个地方相当于一个连接器 void HttpServer::ev_handler(struct mg_connection *nc, int ev, void *p) { if (ev == MG_EV_HTTP_REQUEST) { mg_serve_http(nc, (struct http_message *) p, s_http_server_opts); } } //初始化设置项,使用端口与windows路径创建连接管理器与连接配置项 void HttpServer::Init(const std::string &port, const std::string &path) { //初始化连接管理器 mg_mgr_init(&mgr, NULL); //绑定管理器与端口配置回调函数初始化连接对象 nc = mg_bind(&mgr, port.c_str(), ev_handler); //绑定是否成功 if (nc == NULL) { //连接对象初始化失败退出程序 exit(0); } //创建listen的对应连接 mg_set_protocol_http_websocket(nc); //配置服务器监听的路径 s_http_server_opts.document_root = "D:/HBuilderProject/Babylon"; //开启路径监听 s_http_server_opts.enable_directory_listing = "yes"; } //开始监听 bool HttpServer::Start() { for (;;) { //连接池阻塞主线程进行监听 mg_mgr_poll(&mgr, 1000); } } //关闭监听,这里会释放下级线程池之后可以安全退出 bool HttpServer::Close() { //释放连接管理器对象 mg_mgr_free(&mgr); }
其实大家可以看到使用起来是非常简单的,很快就可以实现对功能的使用,比较进行http监听其实就是就是一个工具性质的东西一样,但是虽然它很小但是它作为一个框架正是它优秀的地方,最终实现的效果也非常的不错,它还不依赖第三方的库非常简洁,当然mongoose也是跨平台的。无论我们是直接将其集成进入系统还是进行二次封装之后编译为静态/动态库都是可行的,我实力推荐!!!
bool HttpServer::Close() 这函数必须有一个返回值吧,要不设置为void
说的没错,但是不重要,看的懂就行