1

发布时间 2023-12-07 22:14:03作者: 做梦当财神

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++代码包含了一系列头文件的引用和命名空间的声明。以下是对代码的解析:

  1. #include "stdafx.h":这是一个预编译头文件,通常用于加速编译过程,包含一些稳定不变的头文件,减少重复编译。
  2. "MyHttpServer.h":自定义的HTTP服务器头文件。
  3. "http/mongoose.h":引用Mongoose库的头文件,该库是一个轻量级的嵌入式Web服务器。
  4. "Pb2Json.h":自定义的头文件,可能包含一些与Protocol Buffers(Pb)和JSON格式相关的功能。
  5. "modp_b64.h":Base64编码解码库的头文件。
  6. "SmartFace.h":自定义的头文件,可能包含人脸识别相关的功能。
  7. <opencv2/core/core.hpp><opencv2/imgproc/imgproc.hpp><opencv2/highgui/highgui.hpp>:OpenCV库的头文件,用于图像处理。
  8. <fstream>:文件流头文件,用于文件的输入输出操作。
  9. <streambuf>:流缓冲区头文件,用于处理输入输出流的缓冲。
  10. "restbed":引用restbed库的头文件,restbed是一个C++11库,用于构建RESTful服务。
  11. using namespace std;:使用std命名空间,这样就可以直接使用标准库中的各种类和函数。
  12. using namespace restbed;:使用restbed命名空间,使得库中的类和函数可以直接使用。
  13. enum 枚举类型:定义了一些错误码,包括 E_OK 表示成功,以及一些可能的错误码如 E_INVALID_FORMATE_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++代码定义了三个函数,分别用于处理字符串匹配和替换的操作。以下是对每个函数的详细解析:

  1. static int has_prefix(const struct mg_str *uri, const struct mg_str &prefix) { ... }
    • 函数名称:has_prefix
    • 参数:const struct mg_str *uriconst struct mg_str &prefix,分别表示待检查的字符串和前缀。
    • 返回类型:int,表示匹配结果。返回非零值表示字符串 uriprefix 开头。
    • 实现:检查 uri 是否以 prefix 开头,通过比较长度和内容的方式,如果满足条件则返回非零值,表示匹配成功。
  2. static int is_equal(const struct mg_str *s1, const struct mg_str *s2) { ... }
    • 函数名称:is_equal
    • 参数:const struct mg_str *s1const struct mg_str *s2,表示待比较的两个字符串。
    • 返回类型:int,表示比较结果。返回非零值表示两个字符串相等。
    • 实现:通过比较长度和内容的方式判断两个字符串是否相等,如果相等则返回非零值,表示比较成功。
  3. 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++代码声明了四个外部函数,其中使用了一些自定义的类型和库。以下是对每个函数的详细解析:

  1. extern bool GetClientInfo(int socket, tstring& ipaddr, int& port);
    • 函数名称:GetClientInfo
    • 参数:
      • int socket:表示套接字描述符(socket descriptor)。
      • tstring& ipaddr:通过引用传递的参数,用于存储客户端的IP地址。
      • int& port:通过引用传递的参数,用于存储客户端的端口号。
    • 返回类型:bool,表示获取客户端信息的操作是否成功。
  2. extern bool GetServerInfo(int socket, tstring& ipaddr, int& port);
    • 函数名称:GetServerInfo
    • 参数:
      • int socket:表示套接字描述符。
      • tstring& ipaddr:通过引用传递的参数,用于存储服务器的IP地址。
      • int& port:通过引用传递的参数,用于存储服务器的端口号。
    • 返回类型:bool,表示获取服务器信息的操作是否成功。
  3. extern int GetLocalAllIP(std::vector<tstring>& IpList);
    • 函数名称:GetLocalAllIP
    • 参数:
      • std::vector<tstring>& IpList:通过引用传递的参数,用于存储本地所有IP地址的字符串向量。
    • 返回类型:int,表示获取本地所有IP地址的操作是否成功,返回的整数值可能表示IP地址的数量或者操作状态。
  4. extern tstring GetLocalIP();
    • 函数名称:GetLocalIP
    • 参数:无
    • 返回类型:tstring,表示获取本地IP地址的操作是否成功,返回的是本地IP地址的字符串。

在上述代码中,tstring 是一个自定义的字符串类型,可以是 std::stringstd::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的部分实现,主要包括构造函数和析构函数。以下是对代码的详细解析:

  1. static MyHttpServer* g_This = NULL;

    • 静态变量 g_This 是一个指向 MyHttpServer 类对象的指针,用于在整个程序中保存当前对象的实例。
    • 初始化为 NULL
  2. MyHttpServer::MyHttpServer()

    • MyHttpServer 类的构造函数。

    • 在构造函数中,将当前对象的指针赋值给 g_This,从而在整个程序中可以通过 g_This 访问当前对象。

    • 通过

      g_AppSetting
      

      对象获取配置信息:

      • 从配置文件中获取算法核心数 core_num
      • 从配置文件中获取访问IP地址 m_strOutIP
    • 调用 SmartFace::Inst().Init(core_num) 初始化 SmartFace 模块,传入算法核心数。

  3. 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++代码定义了一个模板声明,使用了两个模板参数 REQRESP

解析:

  • template<class REQ, class RESP>:这是一个模板声明,表示接下来定义的类、函数、结构体等是一个模板,其中 REQRESP 是模板参数。这意味着,在实例化时可以为 REQRESP 提供具体的类型,从而使模板适用于不同的数据类型。

例如,如果这是一个类的声明,可以在类内部使用 REQRESP 作为数据成员的类型,而在实例化时,可以指定具体的数据类型。

template<class REQ, class RESP>
class ExampleClass {
public:
 REQ request;
 RESP response;
于处理HTTP响应,
 // Other members and methods
};

在上面的例子中,ExampleClass 是一个使用 REQRESP 作为数据成员类型的类模板。



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_methods_put_methods_delete_methods_post_method:表示HTTP请求的不同方法(GET、PUT、DELETE、POST)的mg_str结构体。
  • 事件处理:
    • switch (ev):根据Mongoose库中的事件类型进行不同的处理。
      • MG_EV_ACCEPTMG_EV_CONNECTMG_EV_CLOSE:这些事件目前没有具体的处理,只是保留了break语句。
      • MG_EV_HTTP_REQUEST:处理HTTP请求事件。
        • 通过检查URI前缀,确定调用哪个具体的处理函数(例如,OnReponsePb)来处理不同的API请求。
        • 如果URI以指定的前缀(getallinfogetinfoverify)开头,则调用相应的 OnReponsePb 函数。
        • 否则,使用 mg_serve_http 函数提供静态内容的服务(Serve static content)。

总体来说,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 提供。