手把手教你 用C++实现一个 可持久化 的http_server
前言
本文介绍一个有趣的 通过C++实现的 持久化的http_server demo,这样我们通过http通信之后的数据可以持久化存储,即使server挂了,数据也不会丢失。我们的http_sever 也就能够真正得作为一个后端server了。
本身持久化这个能力是数据库提供的,像通用的http交互数据都会通过SQL server或者MySQL这样的存储系统来存储关系型数据,而这里我只是调度了一个单机存储引擎作为持久化存储。
主要用到的一些技术:
- mongoose C语言 网络通信库,在此库基础上实现了一个C++的httpserver
- Rocksdb 单机存储引擎,作为持久化通信数据的存储。
- 通过模版工厂来优雅得创建http url 和 对应其操作的实现。
代码地址:PersistentHttpserver
实现过程
1. HTTPSERVER C++封装
这里mongoose的通信库基本都已经实现了http应用层及以下的通信接口的封装,包括接受http协议的数据并解析或者封装成http请求并发送,我这里需要做的仅仅是做一些接口调用使用C++实现就可以了。
基本接口如下:
class HttpServer {public:HttpServer() {}~HttpServer() {Close();if (kv_engine_) {delete kv_engine_;kv_engine_ = nullptr;}}void Init(const std::string &port); // Init some variablebool Start(); // Start a http server with a portbool Close();// Send a message as a http requeststatic void SendHttpRsp(mg_connection *connection, std::string rsp);static mg_serve_http_opts s_server_option;static KVEngine *kv_engine_; // For persistent the dataprivate:// Listen the event on the portstatic void OnHttpEvent(mg_connection *connection, int event_type,void *event_data);// Handle the http request with the definite url.static void HandleHttpEvent(mg_connection *connection,http_message *http_req);std::string m_port_;mg_mgr m_mgr_;
};
2. Rocksdb单机引擎使用
大家需要高级功能可以扩展,这里仅仅是使用了一些基本的接口调度起了rocksdb
#pragma once#include <iostream>
#include <string>#include "rocksdb/db.h"
#include "rocksdb/options.h"class KVEngine {public:KVEngine(std::string path) : path_(path) {}~KVEngine() {if (db_) {delete db_;db_ = nullptr;}}void Init() {opt_.create_if_missing = true;if (Open() != "ok") {std::cout << "Open db failed " << std::endl;}}std::string Open() {auto s = rocksdb::DB::Open(opt_, path_, &db_);if (!s.ok()) {return s.ToString();}return "ok";}std::string Get(const std::string& key) {if (nullptr == db_) {return "db_ is nullptr, please init it.";}std::string tmp_val;auto s = db_->Get(rocksdb::ReadOptions(), key, &tmp_val);if (!s.ok()) {return "not ok";}return tmp_val;}std::string Put(const std::string& key, const std::string& val) {if (nullptr == db_) {return "db_ is nullptr, please init it.";}auto s = db_->Put(rocksdb::WriteOptions(), key, val);if (!s.ok()) {std::cout << "Put failed " << s.ToString() << std::endl;return s.ToString();}return "ok";}private:std::string path_;rocksdb::DB* db_;rocksdb::Options opt_;
}
3. 模版工厂来创建 url 及其 handler
通过如下模版工厂,我们后续增加更多的URL的时候,不需要更改httpserver.cpp源码 ,仅仅需要增加一个扩展类 及其 实现,并将这个映射添加到全局映射表中就可以了。
template <class OperationType_t>
class OperationRegister {
public:virtual OperationType_t* CreateOperation(const std::string& op_name, mg_connection* conn, http_message* hm) = 0;protected:OperationRegister() = default;virtual ~OperationRegister() = default;
};// Factory class template
template <class OperationType_t>
class OperationFactory {
public:// Single pattern of the factorystatic OperationFactory<OperationType_t>& Instance() {static OperationFactory<OperationType_t> instance;return instance;}void RegisterOperation(const std::string& op_name,mg_connection* conn, http_message* hm,OperationRegister<OperationType_t>* reg) {operationRegister[op_name] = reg;}OperationType_t* GetOperation(const std::string& op_name,mg_connection* conn, http_message* hm) {if (operationRegister.find(op_name) != operationRegister.end()) {return operationRegister[op_name]->CreateOperation(op_name, conn, hm);}return nullptr;}private:// We don't allow to constructor, copy constructor and align constructorOperationFactory() = default;~OperationFactory() = default;OperationFactory(const OperationFactory&) = delete;const OperationFactory& operator= (const OperationFactory&) = delete;std::map<std::string, OperationRegister<OperationType_t>* > operationRegister;
};// An template class to create the detail Operation
template <class OperationType_t, class OperationImpl_t>
class OperationImplRegister : public OperationRegister<OperationType_t> {
public:explicit OperationImplRegister(const std::string& op_name, mg_connection* conn, http_message* hm) {OperationFactory<OperationType_t>::Instance().RegisterOperation(op_name, conn, hm, this);}OperationType_t* CreateOperation(const std::string& op_name, mg_connection* conn, http_message* hm) {return new OperationImpl_t(op_name, conn, hm);}
};
后续仅仅需要将对应的URL 字符串 及其实现类添加到如下映射表中就可以了。
// Register all the http request's input string and their Class pointer.
void InitializeAllOp(mg_connection* conn, http_message* hm) {static bool initialize = false;if (!initialize) {static OperationImplRegister<Url, GetValue>getValue("/test/getvalue", conn, hm);static OperationImplRegister<Url, SetValueUrl>setValue("/test/setvalue", conn, hm);static OperationImplRegister<Url, RouteUrl>routeUrl("/", conn, hm);initialize = true;}
}
我们在实际HandleHttpEvent
逻辑中就不需要做任何更改,十分友好得提升了代码得可扩展性。
void HttpServer::HandleHttpEvent(mg_connection *connection, http_message *http_req) {std::string req_str = std::string(http_req->message.p, http_req->message.len);std::string url = std::string(http_req->uri.p, http_req->uri.len);InitializeAllOp(connection, http_req);// Register the operation for the urlauto *judge = new JudgeOperation(connection, http_req);auto res = judge->Judge(url);if (res != "ok") {SendHttpRsp(connection, res);}
}
关于模版工厂的细节可以参考:C++ 通过模版工厂实现 简单反射机制
编译及使用
1. 编译
编译之前需要确保测试环境已经成功安装了rocksdb。
git clone https://github.com/BaronStack/PersistentHttpserver.git
cd PersistentHttpserver
make httpserver
rocksdb的on mac安装:brew install rocksdb
rocksdb的on linux安装:rocksdb-Install
2. 使用
第一个console :
./httpserver
第二个console:
╰─$ curl -d "value=firstvalue" 127.0.0.1:7999/test/setvalue { "result": ok }
设置了一个数值之后可以看到httpserver运行的目录处 生成了一个db目录:
db |-- 000010.sst |-- 000013.sst |-- 000016.sst |-- 000019.sst |-- 000025.sst |-- 000030.log |-- CURRENT |-- IDENTITY |-- LOCK |-- LOG |-- MANIFEST-000029 |-- OPTIONS-000029 `-- OPTIONS-000032
停止第一个./httpserver 进程,重新运行,在第二个终端再此输入获取数据的请求命令
╰─$ curl -d "value=firstvalue" 127.0.0.1:7999/test/getvalue { "result": firstvalue }
可以看到能够获取到重启server之前的数据。
有了针对HTTP-SERVER的持久化能力和友好的可扩展性代码,那我就可以持续玩一些有持久化能力的用户需求了。
当然实际中的httpserver请求上层的封装到底层的存储服务都会复杂千万倍,正真能够支持分布式一致性服务的底层存储 不论是newSQL还是NoSQL都会是非常复杂的实现过程。
相关文章:

【SVN多用户开发】代码冲突解决办法
SVN是一款集中式的代码存储工具,可以帮助多个用户协同开发同一应用程序。 但是SVN不能完全代替人工操作,有时也需要程序员自己进行沟通确认有效的代码。 下面就简单的看一下,常见的代码冲突以及解决方法。 总结起来,无非是&#x…

Java项目:在线宠物商店系统(java+SSM+mysql+maven+tomcat)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能:本系统分用户前台和管理员后台。 系统包括用户的注册登录,狗狗的展示购物车添加以及下 单支付购买,后台有管理员用户,可以操作狗狗的品种&…

字符串中的数字排序
2019独角兽企业重金招聘Python工程师标准>>> public static String getBusiScope(String busiScope){ String regex "\\d{1,2}"; String busiStr""; Pattern pattern Pattern.compile(regex); Matcher matcher pattern.matcher(busiScope…

oo第二单元总结
第二单元总结 第一次作业 一、设计策略 本次作业采用FAFS算法,可直接用输入线程与电梯线程交互,调度器暂时不需要参与,故一共设计三个类三线程:Main类、elevator类及input类,main线程、elevator线程及input线程。main线…

Rocksdb iterator 的 Forward-scan 和 Reverse-scan 的性能差异
前言 最近在读 MyRocks 存储引擎2020年的论文,因为这个存储引擎是在Rocksdb之上进行封装的,并且作为Facebook 内部MySQL的底层引擎,用来解决Innodb的空间利用率低下 和 压缩效率低下的问题。而且MyRocks 在接入他们UDB 之后成功达成了他们的…

Java知多少(29)覆盖和重载
在类继承中,子类可以修改从父类继承来的方法,也就是说子类能创建一个与父类方法有不同功能的方法,但具有相同的名称、返回值类型、参数列表。如果在新类中定义一个方法,其名称、返回值类型和参数列表正好与父类中的相同࿰…

Java项目:清新论坛系统(java+SSM+mysql+maven+tomcat)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能:本系统分用户前台和管理员后台。 用户前台主要功能有: 用户注册 用户登录 浏览帖子 回复帖子 修改个人资料 管理员后台的功能有: 管理论坛版块 用户管…

JUnit4.11 理论机制 @Theory 完整解读
最近在研究JUnit4,大部分基础技术都是通过百度和JUnit的官方wiki学习的,目前最新的发布版本是4.11,结合代码实践,发现官方wiki的内容或多或少没有更新,Theory理论机制章节情况尤为严重,不知道这章wiki对应的…

树链剖分——线段树区间合并bzoj染色
线段树区间合并就挺麻烦了,再套个树链就更加鬼畜,不过除了代码量大就没什么其他的了。。 一些细节:线段树每个结点用结构体保存,pushup等合并函数改成返回一个结构体,这样好写一些 struct Seg{int lc,rc,tot;Seg(){lcr…

MyRocks: 为facebool 的社交图谱服务的LSM-tree存储引擎
文章目录概览1. UDB 架构2. UDB 表格式3. Rocksdb:针对flash存储优化过的第三方库3.1 Rocksdb架构3.2 为什么选择Rocksdb4. MyRocks / Rocksdb 开发历程4.1 设计目标4.2 性能挑战4.2.1 降低CPU的消耗4.2.2 降低range-scan 的延时消耗4.2.3 磁盘空间和Compaction 的一…

Java项目:精品酒店管理系统(java+SSM+mysql+maven+tomcat)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能:主要功能主要功能会员管理,住客管理,房间管 理,系统管理,以及一些重要数据的展示导出维护等等; 二、项目运行 环境配置&…

iOS自动布局一
Align: Pin: 转载于:https://www.cnblogs.com/123qw/p/4404167.html

C#实现路由器断开连接,更改公网ip
publicstaticvoidDisconnect(){stringurl "断 线"; stringuri "http://192.168.1.1/userRpm/StatusRpm.htm?Disconnect"System.Web.HttpUtility.UrlEncode(url, System.Text.Encoding.GetEncoding("gb2312")) "&wan1"; str…

Go中的iota
当时在学习Iota这个知识点的时候仅仅是一笔掠过,比如这种 const(aiotab c) 一眼看出他怎么使用的时候就觉得自己已经懂得了 再到后来看到这样的例子 const(a 5*iotab c )以及 const(a 1<<(10*iota)bc ) 第一…

从 SSLTLS 的底层实现来看 网络安全的庞大复杂体系
文章目录前言1. HTTP协议通信的问题1.1 tcpdump 抓取http 请求包1.2 报文分析1.3 HTTP 协议问题2. SSL & TLS 协议的基本介绍和历史演进3. TLS 1.2 实现加密传输的过程3.1 TLS HandShake 协议概览3.2 第一次握手:ClientHello3.3 第二次握手:从Server…

UICollectionView
UICollectionView 多列的UITableView,最简单的形式,类似于iBooks中书架的布局,书架中放着你下载的和购买的电子书。 最简单的UICollectionView是一个GridView,可以多列的方式进行展示。 包含三部分,都是UIView的子类: …

Java项目:课程资源管理+在线考试平台(java+SSH+mysql+maven+tomcat)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能包括: 管理员可以增删改查教材、教材商、入库教材、用户(用 户包括学生和教师)可以对教材商、教材进行。xcel的导入 导出操作。教师可以领取入库的教材,可以退还教…

python twisted 笔记
2019独角兽企业重金招聘Python工程师标准>>> 1.Twisted框架构建简单的C/S 要写一个基于twisted框架的服务器,你要实现事件处理器,它处理诸如一个新的客户端连接、新的数据到达和客户端连接中断等情况。 在Twisted中,你的事件处理器定义在一个…

决策树J48算法
1. J48原理 2. 举例 3. 总结 1. J48原理 基于从上到下的策略,递归的分治策略,选择某个属性放置在根节点,为每个可能的属性值产生一个分支,将实例分成多个子集,每个子集对应一个根节点的分支,然后在每个分支…

分布式系统 一致性模型的介绍 以及 zookeeper的 “线性一致性“ 讨论
文章目录1. 一致性 概览1.1 分布式系统的 “正确性”1.2 线性一致性(Linearizability)1.3 顺序一致性(Sequential consistency)1.4 因果一致性(Casual consistency)1.5 最终一致性(Eventual consistency)2. Zookeeper 的 “线性一致性” 问题3. 参考一致性算是分布式系统的定位…

Java项目:(小程序)全套商城系统(spring+spring mvc+mybatis+layui+微信小程)
源码获取:博客首页 "资源" 里下载! 一、项目简述 本系统功能包括: 商品模块: 商品添加、规格设置,商品上下架等 订单模块: 下单、购物车、支付,发货、收货、评 退款等 营销模块: 积分、优惠券、分销、砍价、拼团、秒 多…

【转】[退役]纪念我的ACM——headacher@XDU
转自:http://hi.baidu.com/headacher/item/5a2ce1d50609091b20e25022 退役了,是时候总结一下我ACM的生涯了。虽然很舍不得,但这段回忆很值得纪念。ACM生涯虽然结束,但是新生活总要继续,还有很多东西需要我去学习&#…

VMware扩大硬盘后修改Linux逻辑卷大小
一、背景随着业务的不断成熟,数据库积累的数据也越来越多了。前些天发现服务器的磁盘将要满了。因此向虚拟化管理员申请增加磁盘空间。由于这个系统是建立在威睿的vSphere平台上的,因此虚拟化管理员只简单地通过 VMware vSphere Client 扩大了磁盘空间&a…

axios与ajax区别
1.jQuery ajax $.ajax({ type: POST, url: url, data: data, dataType: dataType, success: function () {}, error: function () {}});优缺点: 本身是针对MVC的编程,不符合现在前端MVVM的浪潮基于原生的XHR开发,XHR本身的架构不清晰,已经有…

单机 “5千万以上“ 工业级 LRU cache 实现
文章目录前言工业级 LRU Cache1. 基本架构2. 基本操作2.1 insert 操作2.2 高并发下 insert 的一致性/性能 保证2.3 Lookup操作2.4 shard 对 cache Lookup 性能的影响2.4 Erase 操作2.5 内存维护3. 优化前言 近期做了很多 Cache 优化相关的事情,因为对存储引擎较为熟…

Java项目:校园人力人事资源管理系统(java+Springboot+ssm+mysql+jsp+maven)
源码获取:博客首页 "资源" 里下载! 校园人力资源管理系统:学校部门管理,教室管理,学历信息管理,职务,教师职称,奖励,学历,社会关系,工作…

GPS部标平台的架构设计(十)-基于Asp.NET MVC构建GPS部标平台
在当前很多的GPS平台当中,有很多是基于asp.NETsiverlight开发的遗留项目,代码混乱而又难以维护,各种耦合和关联,要命的是界面也没见到比Javascript做的控件有多好看,随着需求的增多,平台已经臃肿不堪。 设计…

关于CSDN不给任何通知强制关闭我的6年博客,我深表痛心
关于CSDN不给任何通知强制关闭我的6年博客,我深表痛心。最近有很长一段时间没有去csdn博客了, 前几天去看的时候发现博客被封闭了。 我联系了管理员,但是没有得到任何回复。 我猜想,可能是不是我在博客文章里面加入 自己网站的网…

Vue 环境搭建(win10)
1.安装node node官网安装地址 推荐安装稳定版本(LTS)以及安装路径为系统盘(C) 查看node安装成功否 注释:以下命令使用 命令提示符(管理员)权限,win10 对user权限的限制了访问权限。node -v 查看…

Java项目:化妆品商城系统(java+Springboot+ssm+mysql+jsp+maven)
源码获取:博客首页 "资源" 里下载! 一、项目简述 本系统主要实现的功能有: 网上商城系统,前台后台管理,用户注册,登录,上架展示,分组展示,搜索,收…