MyHttpServer.cpp
#include "stdafx.h"
#include "MyHttpServer.h"
#include "http/mongoose.h"
#include "Pb2Json.h"
#include "modp_b64.h"
#include "SmartFace.h"
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <fstream>
#include <streambuf>
#include "restbed"
using namespace std;
using namespace restbed;
enum
{
E_OK = 200,
E_INVALID_FORMAT=1000,
E_INVALID_PARAM=1001,
E_ALGORITHM_ERR=1002,
E_EXCUTE_FAILED=1003,
};
using namespace std;
这段C++代码包含了一系列头文件的引用和命名空间的声明。以下是对代码的解析:
#include "stdafx.h":这是一个预编译头文件,通常用于加速编译过程,包含一些稳定不变的头文件,减少重复编译。"MyHttpServer.h":自定义的HTTP服务器头文件。"http/mongoose.h":引用Mongoose库的头文件,该库是一个轻量级的嵌入式Web服务器。"Pb2Json.h":自定义的头文件,可能包含一些与Protocol Buffers(Pb)和JSON格式相关的功能。"modp_b64.h":Base64编码解码库的头文件。"SmartFace.h":自定义的头文件,可能包含人脸识别相关的功能。<opencv2/core/core.hpp>、<opencv2/imgproc/imgproc.hpp>、<opencv2/highgui/highgui.hpp>:OpenCV库的头文件,用于图像处理。<fstream>:文件流头文件,用于文件的输入输出操作。<streambuf>:流缓冲区头文件,用于处理输入输出流的缓冲。"restbed":引用restbed库的头文件,restbed是一个C++11库,用于构建RESTful服务。using namespace std;:使用std命名空间,这样就可以直接使用标准库中的各种类和函数。using namespace restbed;:使用restbed命名空间,使得库中的类和函数可以直接使用。enum枚举类型:定义了一些错误码,包括E_OK表示成功,以及一些可能的错误码如E_INVALID_FORMAT、E_INVALID_PARAM等。
总体来说,这段代码主要是为了构建一个HTTP服务器,并可能涉及到一些与图像处理、人脸识别、Protocol Buffers、JSON等相关的功能。
static int has_prefix(const struct mg_str *uri, const struct mg_str &prefix) {
return uri->len >= prefix.len && memcmp(uri->p, prefix.p, prefix.len) == 0;
}
static int is_equal(const struct mg_str *s1, const struct mg_str *s2) {
return s1->len == s2->len && memcmp(s1->p, s2->p, s2->len) == 0;
}
static void Replace(std::string& str, const std::string& pattern, const std::string& newpat){
int count = 0;
const size_t nsize = newpat.size();
const size_t psize = pattern.size();
for (size_t pos = str.find(pattern, 0);
pos != std::string::npos;
pos = str.find(pattern, pos + nsize)){
str.replace(pos, psize, newpat);
count++;
}
}
这段C++代码定义了三个函数,分别用于处理字符串匹配和替换的操作。以下是对每个函数的详细解析:
static int has_prefix(const struct mg_str *uri, const struct mg_str &prefix) { ... }:- 函数名称:
has_prefix - 参数:
const struct mg_str *uri和const struct mg_str &prefix,分别表示待检查的字符串和前缀。 - 返回类型:
int,表示匹配结果。返回非零值表示字符串uri以prefix开头。 - 实现:检查
uri是否以prefix开头,通过比较长度和内容的方式,如果满足条件则返回非零值,表示匹配成功。
- 函数名称:
static int is_equal(const struct mg_str *s1, const struct mg_str *s2) { ... }:- 函数名称:
is_equal - 参数:
const struct mg_str *s1和const struct mg_str *s2,表示待比较的两个字符串。 - 返回类型:
int,表示比较结果。返回非零值表示两个字符串相等。 - 实现:通过比较长度和内容的方式判断两个字符串是否相等,如果相等则返回非零值,表示比较成功。
- 函数名称:
static void Replace(std::string& str, const std::string& pattern, const std::string& newpat) { ... }:- 函数名称:
Replace - 参数:
std::string& str,表示待替换的字符串;const std::string& pattern,表示待替换的模式;const std::string& newpat,表示替换后的新模式。 - 返回类型:
void,因为是在原字符串上直接进行替换操作。 - 实现:使用循环和
std::string::find方法,在字符串str中查找所有匹配pattern的位置,并进行替换。每次找到一个匹配项,就将其替换为newpat。循环直到字符串中不再存在匹配项。在替换的过程中,记录替换的次数。
- 函数名称:
extern bool GetClientInfo(int socket, tstring& ipaddr, int& port);
extern bool GetServerInfo(int socket, tstring& ipaddr, int& port);
extern int GetLocalAllIP(std::vector<tstring>& IpList);
extern tstring GetLocalIP();
这段C++代码声明了四个外部函数,其中使用了一些自定义的类型和库。以下是对每个函数的详细解析:
extern bool GetClientInfo(int socket, tstring& ipaddr, int& port);- 函数名称:
GetClientInfo - 参数:
int socket:表示套接字描述符(socket descriptor)。tstring& ipaddr:通过引用传递的参数,用于存储客户端的IP地址。int& port:通过引用传递的参数,用于存储客户端的端口号。
- 返回类型:
bool,表示获取客户端信息的操作是否成功。
- 函数名称:
extern bool GetServerInfo(int socket, tstring& ipaddr, int& port);- 函数名称:
GetServerInfo - 参数:
int socket:表示套接字描述符。tstring& ipaddr:通过引用传递的参数,用于存储服务器的IP地址。int& port:通过引用传递的参数,用于存储服务器的端口号。
- 返回类型:
bool,表示获取服务器信息的操作是否成功。
- 函数名称:
extern int GetLocalAllIP(std::vector<tstring>& IpList);- 函数名称:
GetLocalAllIP - 参数:
std::vector<tstring>& IpList:通过引用传递的参数,用于存储本地所有IP地址的字符串向量。
- 返回类型:
int,表示获取本地所有IP地址的操作是否成功,返回的整数值可能表示IP地址的数量或者操作状态。
- 函数名称:
extern tstring GetLocalIP();- 函数名称:
GetLocalIP - 参数:无
- 返回类型:
tstring,表示获取本地IP地址的操作是否成功,返回的是本地IP地址的字符串。
- 函数名称:
在上述代码中,tstring 是一个自定义的字符串类型,可以是 std::string 或 std::wstring 的别名,根据具体的实现而定。这些函数声明表明它们是外部函数,可能在其他文件中定义了其实际实现。这些函数看起来涉及网络编程,用于获取客户端和服务器的信息,以及获取本地的IP地址信息。
static MyHttpServer* g_This = NULL;
MyHttpServer::MyHttpServer()
{
g_This = this;
int core_num=g_AppSetting.GetIniInt("algo","core_num",4);
m_strOutIP=g_AppSetting.GetString("app","access_ip","127.0.0.1");
SmartFace::Inst().Init(core_num);
}
MyHttpServer::~MyHttpServer()
{
g_This = NULL;
SmartFace::Inst().Unit();
}
这段C++代码是一个类MyHttpServer的部分实现,主要包括构造函数和析构函数。以下是对代码的详细解析:
-
static MyHttpServer* g_This = NULL;:- 静态变量
g_This是一个指向MyHttpServer类对象的指针,用于在整个程序中保存当前对象的实例。 - 初始化为
NULL。
- 静态变量
-
MyHttpServer::MyHttpServer():-
MyHttpServer类的构造函数。 -
在构造函数中,将当前对象的指针赋值给
g_This,从而在整个程序中可以通过g_This访问当前对象。 -
通过
g_AppSetting对象获取配置信息:
- 从配置文件中获取算法核心数
core_num。 - 从配置文件中获取访问IP地址
m_strOutIP。
- 从配置文件中获取算法核心数
-
调用
SmartFace::Inst().Init(core_num)初始化 SmartFace 模块,传入算法核心数。
-
-
MyHttpServer::~MyHttpServer():MyHttpServer类的析构函数。- 在析构函数中,将
g_This设置为NULL,表示当前对象已经被销毁。 - 调用
SmartFace::Inst().Unit()对 SmartFace 模块进行清理和释放资源的操作。
总体来说,这段代码主要是在对象的构造和析构过程中,管理 g_This 静态指针,以及通过配置文件获取参数并初始化 SmartFace 模块。这个模块的具体实现和功能在代码中没有给出,但根据函数的命名和调用,可以猜测它可能涉及到人脸识别或者其他相关的算法。
#define DECLARE_API(METHODAPI) static mg_str METHODAPI = MG_STR("/face/"#METHODAPI)
这段C++代码是一个宏定义,用于创建一个静态 mg_str 变量,并初始化为表示特定路径的 mg_str 对象。以下是对代码的详细解析:
解析:
DECLARE_API(METHODAPI):这是一个宏定义,定义了一个宏,该宏接受一个参数METHODAPI,用于构造特定路径的mg_str对象。static mg_str METHODAPI:这是一个静态变量声明,类型为mg_str,用于存储一个表示特定路径的mg_str对象。MG_STR("/face/"#METHODAPI):这是一个宏MG_STR的调用,其目的是将拼接的字符串 "/face/" 和METHODAPI转换为mg_str类型。#METHODAPI是字符串化操作,将METHODAPI参数转换为字符串。
通过使用这个宏,可以方便地定义和初始化 mg_str 变量,避免手动构造 mg_str 对象,使代码更加简洁和易读。例如,如果使用 DECLARE_API(GET_INFO),则会生成一个静态 mg_str 变量,表示路径为 "/face/GET_INFO" 的 mg_str 对象。
template<class T>
void OnReponsePb(struct mg_connection *nc, T& resp) {
// 将Protocol Buffers消息转换为JSON字符串
std::string respStr;
MylibJson2Pb::PbMsg2JsonStr(resp, respStr);
// 发送HTTP响应
mg_printf(nc, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %d\r\n\r\n%s",
(int)respStr.length(), respStr.c_str());
}
这段C++代码定义了一个模板函数 OnReponsePb,该函数用于处理HTTP响应,并将Protocol Buffers(Pb)消息转换为JSON格式后发送给客户端。以下是对代码的详细解析:
解析:
template<class T>:这是一个模板声明,表示接下来定义的函数OnReponsePb是一个模板函数,其参数类型T是模板参数。void OnReponsePb(struct mg_connection *nc, T& resp):这是模板函数的定义,接受两个参数,一个是指向mg_connection结构的指针nc,另一个是模板参数T的引用resp。std::string respStr;:声明一个字符串变量respStr,用于存储将Protocol Buffers消息转换为JSON格式后的字符串。MylibJson2Pb::PbMsg2JsonStr(resp, respStr);:调用PbMsg2JsonStr函数,该函数位于命名空间MylibJson2Pb中,用于将Protocol Buffers消息resp转换为JSON字符串,并存储在respStr中。mg_printf(nc, "HTTP/1.1 200 OK\r\n" ...):使用mg_printf函数发送HTTP响应。"HTTP/1.1 200 OK\r\n":表示HTTP响应状态为200 OK。"Content-Type: text/plain\r\n":表示响应内容的类型为纯文本。"Content-Length: %d\r\n\r\n%s":表示响应内容的长度和内容。%d和%s分别被(int)respStr.length()和respStr.c_str()替换,以确保正确的长度和内容被发送。
这个函数的作用是将Protocol Buffers消息转换为JSON格式,并通过HTTP协议发送给客户端。
template<class REQ, class RESP>
这段C++代码定义了一个模板声明,使用了两个模板参数 REQ 和 RESP。
解析:
template<class REQ, class RESP>:这是一个模板声明,表示接下来定义的类、函数、结构体等是一个模板,其中REQ和RESP是模板参数。这意味着,在实例化时可以为REQ和RESP提供具体的类型,从而使模板适用于不同的数据类型。
例如,如果这是一个类的声明,可以在类内部使用
REQ和RESP作为数据成员的类型,而在实例化时,可以指定具体的数据类型。template<class REQ, class RESP> class ExampleClass { public: REQ request; RESP response; 于处理HTTP响应, // Other members and methods };在上面的例子中,
ExampleClass是一个使用REQ和RESP作为数据成员类型的类模板。
void OnReponsePb(struct mg_connection *nc, struct http_message *hm, MyHttpServer* pThis) {
tstring uri, reqStr, respStr;
// 从http_message结构中获取uri和body的内容
uri.assign(hm->uri.p, hm->uri.len);
reqStr.assign(hm->body.p, hm->body.len);
REQ req; // 定义请求的Protocol Buffers消息对象
RESP resp; // 定义响应的Protocol Buffers消息对象
// 将JSON格式的请求字符串转换为Protocol Buffers消息对象
if (!MylibJson2Pb::JsonStr2PbMsg(reqStr, req)) {
KK_INFO("faile to load json: %s", reqStr.c_str());
// 处理转换失败的情况,设置响应的状态和消息,并发送响应
resp.set_status(E_INVALID_FORMAT);
resp.set_message("failed to load json");
OnReponsePb(nc, resp);
}
// 调用MyHttpServer类的process方法处理请求
pThis->process(req, resp);
// 设置成功的状态和消息
resp.set_status(E_OK);
resp.set_message("success");
// 发送处理后的响应消息
OnReponsePb(nc, resp);
}
这段C++代码定义了一个函数 OnReponsePb,该函数用于处理HTTP响应,其中涉及解析HTTP请求消息,将JSON格式的请求转换为Protocol Buffers消息,然后调用 process 方法处理请求,最终将响应消息以JSON格式返回给客户端。
解析:
tstring uri, reqStr, respStr;:声明三个字符串变量,用于存储URI、请求字符串和响应字符串。uri.assign(hm->uri.p, hm->uri.len);:从http_message结构中获取URI信息,将其赋值给uri字符串。reqStr.assign(hm->body.p, hm->body.len);:从http_message结构中获取请求体的信息,将其赋值给reqStr字符串。REQ req;和RESP resp;:定义了两个变量,分别用于存储请求和响应的Protocol Buffers消息。if (!MylibJson2Pb::JsonStr2PbMsg(reqStr, req)) { ... }:调用JsonStr2PbMsg方法,将JSON格式的请求字符串转换为Protocol Buffers消息对象。如果转换失败,则设置响应的状态和消息,并通过递归调用OnReponsePb(nc, resp)发送错误响应。pThis->process(req, resp);:调用process方法处理请求,该方法可能是MyHttpServer类的成员函数,用于处理请求并修改响应。resp.set_status(E_OK);和resp.set_message("success");:设置成功的状态和消息。OnReponsePb(nc, resp);:再次调用OnReponsePb函数,将处理后的响应消息发送给客户端。这里可能存在递归调用的潜在问题,因为在处理请求失败的情况下也调用了相同的函数。
总体来说,这段代码的目的是处理HTTP请求,将JSON格式的请求转换为Protocol Buffers消息,通过调用 process 方法处理请求,并发送处理后的响应消息。
void MyHttpServer::my_ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
static const struct mg_str s_get_method = MG_STR("GET");
static const struct mg_str s_put_method = MG_STR("PUT");
static const struct mg_str s_delete_method = MG_STR("DELETE");
static const struct mg_str s_post_method = MG_STR("POST");
static struct mg_serve_http_opts s_http_server_opts;
s_http_server_opts.document_root = m_strWebRootDir.c_str();
s_http_server_opts.enable_directory_listing = "no";
DECLARE_API(getallinfo);
DECLARE_API(getinfo);
DECLARE_API(verify);
struct http_message *hm = (struct http_message *)ev_data;
struct mg_str key;
switch (ev) {
case MG_EV_ACCEPT:
break;
case MG_EV_CONNECT:
break;
case MG_EV_CLOSE:
break;
case MG_EV_HTTP_REQUEST:
// 处理HTTP请求事件
if (has_prefix(&hm->uri, getallinfo)){
OnReponsePb<SF::GetAllInfo_Req, SF::GetAllInfo_Resp>(nc, hm, this);
} else if (has_prefix(&hm->uri, getinfo)) {
OnReponsePb<SF::GetInfo_Req, SF::GetInfo_Resp>(nc, hm, this);
} else if (has_prefix(&hm->uri, verify)) {
OnReponsePb<SF::Verify_Req, SF::Verify_Resp>(nc, hm, this);
} else {
mg_serve_http(nc, hm, s_http_server_opts); /* Serve static content */
}
break;
default:
//printf("server not handler ev: %d \n", ev);
break;
}
}
这段C++代码定义了一个静态成员函数 my_ev_handler,该函数似乎是一个事件处理器,用于处理Mongoose库(mg)中的不同事件。
解析:
- 静态成员变量:
s_http_server_opts:用于配置Mongoose HTTP服务器选项的结构体。其中设置了文档根目录和是否启用目录列表。
- 预定义常量:
s_get_method、s_put_method、s_delete_method、s_post_method:表示HTTP请求的不同方法(GET、PUT、DELETE、POST)的mg_str结构体。
- 事件处理:
switch (ev):根据Mongoose库中的事件类型进行不同的处理。MG_EV_ACCEPT、MG_EV_CONNECT、MG_EV_CLOSE:这些事件目前没有具体的处理,只是保留了break语句。MG_EV_HTTP_REQUEST:处理HTTP请求事件。- 通过检查URI前缀,确定调用哪个具体的处理函数(例如,
OnReponsePb)来处理不同的API请求。 - 如果URI以指定的前缀(
getallinfo、getinfo、verify)开头,则调用相应的OnReponsePb函数。 - 否则,使用
mg_serve_http函数提供静态内容的服务(Serve static content)。
- 通过检查URI前缀,确定调用哪个具体的处理函数(例如,
总体来说,my_ev_handler 函数是一个事件处理器,主要处理Mongoose库中的不同事件类型,特别是HTTP请求事件,通过检查URI前缀来调用不同的处理函数。
void MyHttpServer::OnResponse(struct mg_connection *nc, const std::string& respStr) {
mg_printf(nc, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %d\r\n\r\n%s",
(int)respStr.length(), respStr.c_str());
}
这段C++代码定义了一个函数 OnResponse,用于向客户端发送HTTP响应。
解析:
void MyHttpServer::OnResponse(struct mg_connection *nc, const std::string& respStr):这是一个成员函数的定义,用于发送HTTP响应。struct mg_connection *nc:表示Mongoose库中的连接结构体,用于发送HTTP响应。const std::string& respStr:表示要发送的HTTP响应内容,以字符串形式传递。
mg_printf(nc, "HTTP/1.1 200 OK\r\n" ...):使用Mongoose库中的mg_printf函数发送HTTP响应。"HTTP/1.1 200 OK\r\n":表示HTTP响应的状态为200 OK。"Content-Type: text/plain\r\n":表示响应内容的类型为纯文本。"Content-Length: %d\r\n\r\n%s":表示响应内容的长度和内容。%d和%s分别被(int)respStr.length()和respStr.c_str()替换,以确保正确的长度和内容被发送。
这个函数的作用是发送HTTP响应,其中状态为200 OK,内容类型为纯文本,具体的内容和长度由参数 respStr 提供。