基於moongoose的c++ http服務端
阿新 • • 發佈:2018-11-01
我最輕量級的c++ http服務端
這只是一個半成品,僅有部分測試函式,需要根據自己的需要做一些修改和完善工作。
可以用作參考來實現一個輕量級的http服務端。
專案組成
標頭檔案http_server.h
#ifndef HTTP_SERVER_H
#define HTTP_SERVER_H
#include <string>
#include <unordered_map>
#include <functional>
#include "mongoose.h"
// 定義http返回callback
typedef void OnRspCallback(mg_connection *c, std::string);
// 定義http請求handler
using ReqHandler = std::function<bool(std::string, std::string, mg_connection *c, OnRspCallback)>;
class HttpServer
{
public:
HttpServer() {}
~HttpServer () {}
void Init(const std::string &port); // 初始化設定
bool Start(); // 啟動httpserver
bool Close(); // 關閉
void AddHandler(const std::string &url, ReqHandler req_handler); // 註冊事件處理函式
void RemoveHandler(const std::string &url); // 移除時間處理函式
static std::string s_web_dir; // 網頁根目錄
static mg_serve_http_opts s_server_option; // web伺服器選項
static std::unordered_map<std::string, ReqHandler> s_handler_map; // 回撥函式對映表
private:
// 靜態事件響應函式
static void OnHttpEvent(mg_connection *connection, int event_type, void *event_data);
static void HandleEvent(mg_connection *connection, http_message *http_req);
static void SendRsp(mg_connection *connection, std::string rsp);
std::string m_port; // 埠
mg_mgr m_mgr; // 連線管理器
};
#endif
原始檔http_control1.cpp
// http_control1.cpp : 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
#include <memory>
#include "http_server.h"
// 初始化HttpServer靜態類成員
mg_serve_http_opts HttpServer::s_server_option;
std::string HttpServer::s_web_dir = "./web";
std::unordered_map<std::string, ReqHandler> HttpServer::s_handler_map;
bool handle_fun1(std::string url, std::string body, mg_connection *c, OnRspCallback rsp_callback)
{
// do sth
std::cout << "handle fun1" << std::endl;
std::cout << "url: " << url << std::endl;
std::cout << "body: " << body << std::endl;
rsp_callback(c, "rsp1");
return true;
}
bool handle_fun2(std::string url, std::string body, mg_connection *c, OnRspCallback rsp_callback)
{
// do sth
std::cout << "handle fun2" << std::endl;
std::cout << "url: " << url << std::endl;
std::cout << "body: " << body << std::endl;
rsp_callback(c, "rsp2");
return true;
}
bool handle_fun3(std::string url, std::string body, mg_connection *c, OnRspCallback rsp_callback)
{
// do sth
std::cout << "handle fun3" << std::endl;
std::cout << "url: " << url << std::endl;
std::cout << "body: " << body << std::endl;
char csSession_Key[100] = { 0 };
mg_str m1;
const char* pc1 = "session_key=DF9A3B1843A526AA&windfarm_ID=1000&windturbine_ID_List=1%23&cmd=parsed_data&data_Type_List=0&ts_Start=1531099800&ts_End=1531114200";
int n1 = strlen(pc1);
m1.p = c->recv_mbuf.buf;
m1.len = c->recv_mbuf.len;
m1.p = pc1;
m1.len = n1;
int nRes = mg_get_http_var(&m1, "session_key", csSession_Key, 100);
const char* pcRes = "<?xml version=\"1.0\" encoding=\"utf-8\"?><string xmlns = \"http://tempuri.org/\">{\"status\":\"OK\",\"windfarm_id\":1000,\"windturbine_id_list\":\"1#\",\"data_type_list\" : []}</string>";
rsp_callback(c, pcRes);
//SendRsp(connection, "<?xml version=\"1.0\" encoding=\"utf-8\"?><string xmlns = \"http://tempuri.org/\">{\"status\":\"OK\",\"windfarm_id\":1000,\"windturbine_id_list\":\"1#\",\"data_type_list\" : []}</string>");
return true;
}
bool handle_fun4(std::string url, std::string body, mg_connection *c, OnRspCallback rsp_callback)
{
// do sth
std::cout << "handle fun4" << std::endl;
std::cout << "url: " << url << std::endl;
std::cout << "body: " << body << std::endl;
rsp_callback(c, "rsp4");
return true;
}
bool handle_fun5(std::string url, std::string body, mg_connection *c, OnRspCallback rsp_callback)
{
// do sth
std::cout << "handle fun5" << std::endl;
std::cout << "url: " << url << std::endl;
std::cout << "body: " << body << std::endl;
rsp_callback(c, "rsp5");
return true;
}
bool GetSessionKey(std::string url, std::string body, mg_connection *c, OnRspCallback rsp_callback)
{
// do sth
std::cout << "handle GetSessionKey" << std::endl;
std::cout << "url: " << url << std::endl;
std::cout << "body: " << body << std::endl;
const char* pcRes = "<?xml version=\"1.0\" encoding=\"utf-8\"?><string xmlns = \"http://tempuri.org/\">{\"status\":\"OK\",\"windfarm_id\":1000,\"cms_vendor\":\"aa\",\"session_key\":\"DF9A3B1843A526AA\",\"key_alive_second\":3600}</string>";
rsp_callback(c, pcRes);
//rsp_callback(c, "<?xml version=\"1.0\" encoding=\"utf-8\"?><string xmlns = \"http://tempuri.org/\">{\"status\":\"OK\",\"windfarm_id\":1000,\"windturbine_id_list\":\"1#\",\"data_type_list\" : []}</string>");
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::string port = "7999";
auto http_server = std::shared_ptr<HttpServer>(new HttpServer);
http_server->Init(port);
// add handler
http_server->AddHandler("/api/fun1", handle_fun1);
http_server->AddHandler("/api/fun2", handle_fun2);
http_server->AddHandler("/api/GetCharacterData", handle_fun3);
http_server->AddHandler("/api/fun4", handle_fun4);
http_server->AddHandler("/api/fun5", handle_fun5);
http_server->AddHandler("/api/GetSessionKey", GetSessionKey);
// http_server->RemoveHandler("/api/fun6");
// http_server->RemoveHandler("/api/fun3");
http_server->Start();
return 0;
}
原始檔http_server.cpp
#include <utility>
#include "http_server.h"
void HttpServer::Init(const std::string &port)
{
m_port = port;
s_server_option.enable_directory_listing = "yes";
s_server_option.document_root = s_web_dir.c_str();
// TODO:其他設定
}
bool HttpServer::Start()
{
mg_mgr_init(&m_mgr, NULL);
mg_connection *connection = mg_bind(&m_mgr, m_port.c_str(), OnHttpEvent);
if (connection == NULL)
return false;
mg_set_protocol_http_websocket(connection);
printf("starting http server at port: %s\n", m_port.c_str());
// loop
while (true)
mg_mgr_poll(&m_mgr, 500); // ms
return true;
}
void HttpServer::OnHttpEvent(mg_connection *connection, int event_type, void *event_data)
{
http_message *http_req = (http_message *)event_data;
switch (event_type)
{
case MG_EV_HTTP_REQUEST:
//case 0:
HandleEvent(connection, http_req);
break;
default:
break;
}
}
static bool route_check(http_message *http_msg, char *route_prefix)
{
if (mg_vcmp(&http_msg->uri, route_prefix) == 0)
return true;
else
return false;
// TODO: 還可以判斷 GET, POST, PUT, DELTE等方法
//mg_vcmp(&http_msg->method, "GET");
//mg_vcmp(&http_msg->method, "POST");
//mg_vcmp(&http_msg->method, "PUT");
//mg_vcmp(&http_msg->method, "DELETE");
}
void HttpServer::AddHandler(const std::string &url, ReqHandler req_handler)
{
if (s_handler_map.find(url) != s_handler_map.end())
return;
s_handler_map.insert(std::make_pair(url, req_handler));
}
void HttpServer::RemoveHandler(const std::string &url)
{
auto it = s_handler_map.find(url);
if (it != s_handler_map.end())
s_handler_map.erase(it);
}
void HttpServer::SendRsp(mg_connection *connection, std::string rsp)
{
// 必須先發送header
mg_printf(connection, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
// 以json形式返回
//mg_printf_http_chunk(connection, "{ \"result\": %s }", rsp.c_str());
mg_printf_http_chunk(connection, "%s", rsp.c_str());
// 傳送空白字元快,結束當前響應
mg_send_http_chunk(connection, "", 0);
}
void HttpServer::HandleEvent(mg_connection *connection, http_message *http_req)
{
std::string req_str = std::string(http_req->message.p, http_req->message.len);
printf("got request: %s\n", req_str.c_str());
// 先過濾是否已註冊的函式回撥
std::string url = std::string(http_req->uri.p, http_req->uri.len);
std::string body = std::string(http_req->body.p, http_req->body.len);
auto it = s_handler_map.find(url);
if (it != s_handler_map.end())
{
ReqHandler handle_func = it->second;
handle_func(url, body, connection, SendRsp);
}
// 其他請求
if (route_check(http_req, "/")) // index page
mg_serve_http(connection, http_req, s_server_option);
else if (route_check(http_req, "/api/hello"))
{
// 直接回傳
SendRsp(connection, "welcome to httpserver");
}
else if (route_check(http_req, "/api/sum"))
{
// 簡單post請求,加法運算測試
char n1[100], n2[100];
double result;
/* Get form variables */
mg_get_http_var(&http_req->body, "n1", n1, sizeof(n1));
mg_get_http_var(&http_req->body, "n2", n2, sizeof(n2));
/* Compute the result and send it back as a JSON object */
result = strtod(n1, NULL) + strtod(n2, NULL);
SendRsp(connection, std::to_string(result));
}
else if (route_check(http_req, "/api/GetCharacterData"))//GetCharacterData
{
/*SendRsp(connection, "<?xml version=\"1.0\"encoding=\"utf-8\"?>"
"<string xmlns=\"http://tempuri.org/\">{\"status\":\"OK\",\"windfarm_id\":1000,\"windturbine_id_list\":\"1#\",\"data_type_list\" : []}< / string>"
);*/
SendRsp(connection, "<?xml version=\"1.0\" encoding=\"utf-8\"?><string xmlns = \"http://tempuri.org/\">{\"status\":\"OK\",\"windfarm_id\":1000,\"windturbine_id_list\":\"1#\",\"data_type_list\" : []}</string>"
);
}
else if (route_check(http_req, "/api/GetWaveFormData"))//GetWaveFormData
{
SendRsp(connection, "<?xml version=\"1.0\" encoding=\"utf-8\"?><string xmlns = \"http://tempuri.org/\">{\"status\":\"OK\", \"windfram_id\" : 1000, \"windTurbine_id_list\" : \"1#\", \"data_list\" : []}</string>"
);
}
else if (route_check(http_req, "/api/GetAlarmrData"))//GetAlarmrData
{
SendRsp(connection, "<?xml version=\"1.0\" encoding=\"utf-8\"?><string xmlns = \"http://tempuri.org/\">{\"status\":\"OK\",\"windfarm_id\":1000,\"windturbine_id_list\":\"1#\",\"data_type_list\" : []}</string>"
);
}
else
{
mg_printf(
connection,
"%s",
"HTTP/1.1 501 Not Implemented\r\n"
"Content-Length: 0\r\n\r\n");
}
}
bool HttpServer::Close()
{
mg_mgr_free(&m_mgr);
return true;
}
我記得參考過一篇部落格,但是實在找不到了,只有工程裡的程式碼,如有人自認原作者請與我聯絡