您的位置:首页 > 理论基础 > 计算机网络

c++利用mongoose实现http服务

2015-11-20 13:20 274 查看
近来在项目中需要实现一个http service的功能。虽然可以通过封装socket自己实现http的发送和解析。但考虑到目前网络上还是有大量的http的解析源码,自己再从头实现一番稍显麻烦。因此在网络上搜刮了一番,看到很多实现http的代码, 无一不体现了其轻量级的特点。然而,虽然轻量级,但从代码的量上来说,为了一个http
service的功能,引入这许多的代码,也着实不是十分情愿呢。后在同事的推荐下选择了mongoose的代码。

mongoose的代码着实轻量,先看看它的特点:

1. 在整个的实现是使用c语言编写

2. 整个代码也只有一个mongoose.c和mongoose.h两个文件, 从引入第三方的考虑上也着实不多。

3. 实现的功能还是非常多的,从使用的层面上来说功能还是比较全面。只不过不知道是否是为了第三方使用的方便还是怎么地,它的代码只用了两个源文件罢了。诸多的功能也大以宏的开始与结束来区分。

4. 示例非常齐全,所有的功能都有单独的示例

然而,不管它实现多少功能,对于我来说只需要三个:

1. 有http的解析等

2. 文件少,使用方便,不需要因为使用一个简单的功能引入大量代码,而且引入的代码着实没有用到。

3. 有完整的示例

当我们拿到一个第三方库或者第三方源码的时候,第一件事情就是看看代码的示例,并且自己动手谢谢测试的代码,完成自己想要的功能。于是,我花了一点时间自己写了一个测试的代码,最后发现测试的时候并不通。虽然它的代码示例很全面,然而对于我们来说,或许在它的代码中,有些函数我们不需要,而有些函数却不再这个示例中使用,因此需要自己测试。耗费了一些时间以后,我个人做了一下的简单封装,算是简单的实现一个http
service的功能,其中使用到了一点c++11的特性。可丢砖头,也可交流。

// File:        basic_http.h
// Description: ---
// Notes:       ---
// Author:      Haust <wyy123_2008@qq.com>
// Revision:    2015-11-19 by Haust

#pragma once

#include "mongoose.h"
#include <map>
#include <string>
#include <functional>

class BasicHttp {
public:
    using handler = std::function<void(std::string, std::string)>;

public:
    virtual ~BasicHttp(){};
  
    void Init(uint32_t port);
    bool Start();
    bool Close();
    bool RegisterHandler(std::string uri, handler f);
    void UnRegisterHandler(std::string uri);
    void Loop(int milli);

    void SendReply(std::string uri, std::string reply);
    void SendError(std::string uri, int errcode, std::string reply);

protected:
    using handler_map = std::map<std::string, handler>;
    using connection_map = std::multimap<std::string, mg_connection*>;

private:
    static void EvHandler(struct mg_connection* nc, int ev, void* ev_data);
    static void HandleRequst(struct mg_connection* nc, int ev, void *ev_data); 

public:
    static handler_map _handlers;
    static connection_map _connections;

    char _port[11];
    struct mg_mgr _mgr;
};
// File:        basic_http.cpp
// Description: ---
// Notes:       ---
// Author:      Haust <wyy123_2008@qq.com>
// Revision:    2015-11-19 by Haust

#include "basic_http.h"

BasicHttp::handler_map BasicHttp::_handlers;
BasicHttp::connection_map BasicHttp::_connections;

void BasicHttp::Init(uint32_t port){
    memset(_port, 0, sizeof(_port));
    snprintf(_port, sizeof(_port), "%u", port);
}

bool BasicHttp::Start(){
    mg_mgr_init(&_mgr, NULL);
    auto nc = mg_bind(&_mgr, _port, EvHandler);

    if(nullptr == nc)
        return false;

    mg_set_protocol_http_websocket(nc);
    return true;
}

bool BasicHttp::Close(){
    mg_mgr_free(&_mgr);
    return true;
}

bool BasicHttp::RegisterHandler(std::string uri, handler f){
    auto it = _handlers.find(uri);
    if(_handlers.end() != it)
        return false;

    return _handlers.emplace(uri, f).second;
}

void BasicHttp::UnRegisterHandler(std::string uri){
    auto it = _handlers.find(uri);
    if(_handlers.end() != it)
        _handlers.erase(it);
}

void BasicHttp::Loop(int milli){
    mg_mgr_poll(&_mgr, milli);
}

void BasicHttp::EvHandler(struct mg_connection* nc, int ev, void* ev_data){
   switch(ev){
        case MG_EV_HTTP_REQUEST:
            HandleRequst(nc, ev, ev_data);
            break;
       default:
           break;
   }
}

void BasicHttp::HandleRequst(struct mg_connection *nc, int ev, void* ev_data){
    http_message* hm = (http_message*)ev_data;
    std::string uri(hm->uri.p, hm->uri.len);

    auto it = _handlers.find(uri);
    if(_handlers.end() == it)
        return;

    _connections.emplace(uri, nc);
    it->second(std::string(hm->query_string.p, hm->query_string.len),
            std::string(hm->body.p, hm->body.len));
}

void BasicHttp::SendReply(std::string uri, std::string reply){
    auto range = _connections.equal_range(uri);
    if(range.first == range.second)
        return;

    auto it = range.first;
    mg_printf(it->second, "HTTP/1.1 200 OK\r\niConnection: close\r\nContent-Type: text/html\r\nContent-Length: %u\r\n\r\n%s\r\n", 
            (uint32_t)reply.length(), reply.c_str());

    it->second->flags |= MG_F_SEND_AND_CLOSE;
    _connections.erase(it);
}

void BasicHttp::SendError(std::string uri, int errcode, std::string reply){
    auto range = _connections.equal_range(uri);
    if(range.first == range.second)
        return;

    auto it = range.first;
    mg_printf(it->second, "HTTP/1.1 %d %s\r\n", errcode, reply.c_str());

    it->second->flags |= MG_F_SEND_AND_CLOSE;
    _connections.erase(it);
}

#include "mongoose.c"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: