近來在項目中需要實現一個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"
