C++ 实现 httpserver (mongoose)

httpserver:

包含内容:C++ 、mongoose、http协议

此次只实现了服务端,客户端没有去实现。最终测试成功

主要针对客户端使用POST方式进行应答,GET方式也可以

客户端使用POST方式上传的信息会通过标准输出函数输出在终端上

代码

main.cpp

// *************************************************
// File name: main.cpp
// Author: xhp  
// Version: 1.0
// Date: 2021/7/21
// Description: C++利用mongoose实现http服务端
// *************************************************

#include 
#include "./http/http_server.h"

                                                                        //初始化HttpServer静态类成员
std::string HttpServer::s_web_dir = ".";                                //当前目录
bool HttpServer::compare_flag = true;                                   //默认将响应体判断结果设成 true
mg_serve_http_opts HttpServer::s_server_option;
std::unordered_map<std::string,ReqHandler> HttpServer::s_handler_map;

/**
* @Description:http应答信息输出函数
* @param  Req_message: 返回的信息字符串
* @param  c: mg_connection结构体定义的指针(mongoose connection)
* @param  rsp_callback: 向服务端返回应答信息的函数指针
* @return none
*/
bool handle_function(std::string Req_message,mg_connection *c,OnRspCallback rsp_callback)
{
    //do sth
    std::cout<<Req_message<<"\n"<<std::endl;                            //输出http请求信息(请求行+消息报头+请求正文)

    rsp_callback(c);                                                    //返回应答信息  "code=0000" 表示成功,其他表示失败

    return true;
}

int main(int argc,char *argv[])
{
    std::string port;                                                   //创建一个string类型的端口
    auto http_server = std::shared_ptr<HttpServer>(new HttpServer);     //创建一个智能指针

    std::cout<<"please input port number : ";
    std::cin>>port;

    http_server->Init(port);
    http_server->AddHandler("/",handle_function);
    http_server->Start();

    return 0;
}

http_server.cpp

// *************************************************
// File name: http_server.cpp
// Author: xhp  
// Version: 1.0
// Date: 2021/7/21
// Description: C++利用mongoose实现http服务端
// *************************************************
#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();               //c_str()将string类型的字符串以char*类型返回
}

/**
* @Description:启动httpserver
* @param  none
* @return 成功: true ,失败: false
*/
bool HttpServer::Start()
{
    mg_mgr_init(&m_mgr,NULL);                                       // 初始化mongoose manager
    mg_connection *connection = mg_bind(&m_mgr,m_port.c_str(),HttpServer::OnHttpEvent);

    if(connection == NULL)
        return false;

    mg_set_protocol_http_websocket(connection);                     //调用此函数将上一步返回给connection的数据与内建的http handler绑定
                                                                    //这样我们的handler才能收到http事件
    printf("starting http server at port : %s , ready !!!\n\n",m_port.c_str());

    while(HttpServer::compare_flag)
        mg_mgr_poll(&m_mgr,500);                                    //ms      通过一直调用mg_mgr_poll接收请求

    std::cout<<"error : respond format error!\n"<<std::endl;        //compare_flag标志位被置为false,表示响应体格式不合规定
    Close();                                                        //关闭并释放所有活动的连接
    return true;
}

/**
* @Description:事件响应函数
* @param  connection: mongoose connection
* @param  event_type: 事件类型
* @param  event_data: 事件数据
* @return none
*/
void HttpServer::OnHttpEvent(mg_connection *connection,int event_type,void *event_data)
{
    if(event_type == MG_EV_HTTP_REQUEST) {
        http_message *http_req = (http_message *)event_data;
        HandleHttpEvent(connection,http_req);
    }
}

/**
* @Description:路径检查函数
* @param  http_msg:  关于HTTP请求的一些信息,http_message是一个HTTP协议存储有关信息的结构体
* @param  route_prefix: 指定的资源定位符(url)
* @return 成功: true ,失败: false
*/
static bool route_check(const http_message *http_msg,const char *route_prefix)
{
    if(mg_vcmp(&http_msg->uri,route_prefix) == 0)                   // http_msg->uri --> "/my_file.html" 
        return true;
    else
        return false;
}

/**
* @Description:处理http事件
* @param  connection: mongoose connection
* @param  http_req: 关于HTTP请求的一些信息,http_message是一个HTTP协议存储有关信息的结构体
* @return none
*/
void HttpServer::HandleHttpEvent(mg_connection *connection, http_message *http_req)
{
    std::string req_str = std::string(http_req->message.p,http_req->message.len);//截取前http_req->message.len长度的字符串

    //先过滤是否已注册的函数回调
    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);

    if(strncmp(body.c_str(),"vgdecoderesult",sizeof("vgdecoderesult")-1) == 0)
        HttpServer::compare_flag = true;
    else
        HttpServer::compare_flag = false;

    auto it = s_handler_map.find(url);          //在s_handler_map中寻找url,将结果返回给it,如果没有找到,就返回s_handler_map.end()
    if(it != s_handler_map.end()) {
        ReqHandler handler_func = it->second;   //second指向handler_funcation,每个url对应一个单独的second
        handler_func(req_str.c_str(),connection,&HttpServer::SendHttpRsp);//这个handler_func在调用handler_function函数
    }

    //其他请求
    if(route_check(http_req,(char*)"/"))        //url比较
        mg_serve_http(connection,http_req,s_server_option);
        
    else {
        mg_printf(
            connection,
            "%s",
            "HTTP/1.1 501 Not Implemented",
            "Content-Length: 0\r\n\r\n"
            );
    }
}

/**
* @Description: http respond
* @param  connection: mongoose connection
* @return none
*/
void HttpServer::SendHttpRsp(mg_connection *connection)
{
    if(HttpServer::compare_flag == true){
        //告诉设备,0000表示成功,1111表示失败
        mg_printf(connection, "%s", 
            "HTTP/1.1 200 OK code=0000\r\n"
            "Transfer-Encoding: chunked\r\n"
            "Content-Type: text/plain; charset=UTF-8\r\n"
            "Content-Length: 0\r\n\r\n"
            );
        
	    mg_printf_http_chunk(connection, "{ \"result\": %s }", "code=0000");// 以json形式返回
    }
    else if(HttpServer::compare_flag == false){
        mg_printf(connection, "%s", 
            "HTTP/1.1 200 OK code=1111\r\n"
            "Transfer-Encoding: chunked\r\n"
            "Content-Type: text/plain; charset=UTF-8\r\n"
            "Content-Length: 0\r\n\r\n"
            );
        
	    mg_printf_http_chunk(connection, "{ \"result\": %s }", "code=1111");// 以json形式返回
    }
    mg_send_http_chunk(connection,"",0);                                    // 发送空白字符块,结束当前响应
}

/**
* @Description: free memory
* @param  none
* @return true
*/
bool HttpServer::Close()
{
    mg_mgr_free(&m_mgr);
    return true;
}

/**
* @Description: add Handler
* @param  url: 资源定位符
* @param  req_handler: 事件处理函数指针
* @return none
*/
void HttpServer::AddHandler(const std::string &url,ReqHandler req_handler)
{
    if(s_handler_map.find(url) != s_handler_map.end())          //找到了url(统一资源定位符),就return出去
        return;
    s_handler_map.insert(std::make_pair(url,req_handler));      //没找到这个url,就把url插入进去
                                                                //make_pair函数是将url和req_handler进行处理后将返回值插入进s_handler_map
}

http_server.h

#pragma once
#include "../mongoose/mongoose.h"
#include 
#include 
#include 
#include 
#include 
#include 

//定义http返回callback
typedef void OnRspCallback(mg_connection *c);
//定义http请求handler
using ReqHandler = std::function<bool (std::string,mg_connection *c,OnRspCallback)>;    //ReqHandler用来保存function返回的一个函数指针

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);                     //注册时间处理函数
    static mg_serve_http_opts s_server_option;                                          //web服务器选项
    static std::string s_web_dir;                                                       //网页根目录
    static bool compare_flag;                                                           //判断响应体内容是否符合要求
    static std::unordered_map<std::string,ReqHandler> s_handler_map;                    //回调函数映射表
                                                                                        //unordered_map 无序关联式容器
                                                                                        //map和unordered_map唯一的区别就是map是有序存储的,
                                                                                        //而unordered_map是无序存储的
private:
    static void SendHttpRsp(mg_connection *connection);                                 //服务端向客户端发送http响应
    static void HandleHttpEvent(mg_connection *connection, http_message *http_req);     //处理http事件
    static void OnHttpEvent(mg_connection *connection,int event_type,void *event_data); //事件响应函数

    std::string m_port;                                                                 //端口
    mg_mgr m_mgr;                                                                       //连接管理器
};

你可能感兴趣的:(C++,c++,http)