1. 程式人生 > >c++利用mongoose實現http服務

c++利用mongoose實現http服務

近來在專案中需要實現一個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 <[email protected]>
// 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 <[email protected]>
// 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"

相關推薦

c++利用mongoose實現http服務

近來在專案中需要實現一個http service的功能。雖然可以通過封裝socket自己實現http的傳送和解析。但考慮到目前網路上還是有大量的http的解析原始碼,自己再從頭實現一番稍顯麻煩。因此在網路上搜颳了一番,看到很多實現http的程式碼, 無一不體現了其輕量級的特

Golang裏實現Http服務器並解析header參數和表單參數

打印 表單 class per lang accept png Go語言 title 在http服務裏,header參數和表單參數是經常使用到的,本文主要是練習在Go語言裏,如何解析Http請求的header裏的參數和表單參數,具體代碼如下: package server

C#利用Guid實現真隨機數

循環 有效 不為 唯一標識 生成 算法 bsp 目錄 系統目錄 C#中的隨機數可以利用Random類很簡單地生成隨機數,代碼如下: Random rdmNum=new Random();//生成隨機數對象 int ans=rdmNum.Next(a,b);//生成大於大於

C#利用Dapper實現對SQLite的操作

前言 近幾天藉助C#對SQLite的學習,算是對資料庫剛入門吧,三天前寫了一篇C#利用System.Data.SQLite實現對SQLite的操作,其中方法是基於System.Data.SQLite.dll的程式包,後來在youtube和infoworld上看到利用Dapper程式包對資

使用Go語言實現http服務端指定路徑的檔案.

package main import ( "io" "net/http" ) func main() { http.HandleFunc("/", router) http.Listen

Linux shell實現HTTP服務

需求場景 使用代理伺服器 HAProxy 對 Mysql 做負載均衡是常用方案,為提高可用性,當某個 Mysql 出現問題時,例如伺服器故障了,或者資料複製中斷了,最好可以讓 HAProxy 馬上知道,然後停止向其轉發請求 HAProxy 如何知道 Mysql 是否有問題呢? 解決思路 (1)編

Springboot2(24)整合netty實現http服務(類似SpingMvc的contoller層實現

原始碼地址 springboot2教程系列 其它netty檔案有部落格 Springboot2(24)整合netty實現http服務(類似SpingMvc的contoller層實現) Springboot2(25)整合netty實現檔案傳輸 Springb

C++使用CHttpFile實現Http請求

C++實現http請求的程式碼,參照網上的修改了下在mfc中使用 1、HttpClient.h //////////////////////////////////// HttpClient.h #ifndef HTTPCLIENT_H #define HTTPCLIENT

c++ 利用boost 實現檔案操作

對資料夾裡面的檔案進行遍歷操作是基本技能之一,python,perl以及bash等指令碼都很好的實現了檔案遍歷方法,對於c/c++來說,只能通過系統自定的api獲取。雖然資料夾操作本身是呼叫作業系統核心的介面,但畢竟介面不夠友好。 boost不愧是準標準庫,f

C++利用模板實現一個佇列

開頭總結:.利用模板類實現了一個佇列,利用模板的好處是提供泛型程式設計,在儲存資料的時候會適應不同型別的資料,減少了程式碼的書寫,簡化了程式的結構。#include <iostream>

gorilla/mux實現http服務示例

gorilla/mux 小巧玲瓏而十分高效,相容go自帶的http。下載原始碼到本地,編寫如下示例: package main import ( "encoding/json" "fmt" "github.com/gorilla/

c++利用libcurl獲取http網頁的 response headers 等資訊

參考:http://www.update8.com/Program/C++/26438.html libcurl-7.32.0下載地址:http://download.csdn.net/detail/chuanyu/9226175 demo下載地址: http://dow

C++利用boost實現base64編碼解碼

#include <boost/archive/iterators/base64_from_binary.hpp> #include <boost/archive/iterators/binary_from_base64.hpp> #include &

[C#]利用介面實現多型性淺析

所謂的多型性,個人認為說的是相同的程式接受幾段毫不相同的引數而能正常的執行。而在C#中利用介面實現多型性我覺得並不是太嚴謹。我認為要真正實現多型性離不開泛型。 舉個小例子: public interface Iinter { publ

Objective-c利用協議實現回撥函式

定義協議: #import <UIKit/UIKit.h> @protocol myViewDelegate -(void) CallBackFun; @end 呼叫協議: #import <Foundation/Foundation.h>

C#利用HttpListener實現接受上傳檔案

最近一個winform專案想直接用http協議與java端進行雙向通訊,發現HttpListener可以實現http通訊,如果提交form的enctype=application/x-www-form-urlencoded則可以通過HttpUtility.Par

快速利用python搭建http服務,傳輸檔案

開啟cmd 進入你要分享的資料夾 輸入 python -m SimpleHTTPServer 8000 如果提示 No module named SimpleHTTPServer 試一試 p

Visual C#實現HTTP代理服務程式

1   網路代理程式的種類非常多,根據代理服務程式代理的協議不同,分成HTTP代理服務程式、FTP代理服務程式等,執行代理服務程式的伺服器也就稱為HTTP代理伺服器和FTP代理伺服器。在本節中介紹的Web代理服務程式代理的就是HTTP協議。   一.網路代理的型別及實現原理:   網路代理服務根

C#利用反射來判斷對象是否包含某個屬性的實現方法

是否 npr nbsp pro bsp str return ram ret 本文實例展示了C#利用反射來判斷對象是否包含某個屬性的實現方法,對於C#程序設計人員來說有一定的學習借鑒價值。 具體實現代碼如下: 1 /// <summary> 2 /// 利

Http服務實現文件上傳與下載(五)

aaa con 選擇 gethost cte 分隔 數據 gif 開始 一、引言 歡迎大家和我一起編寫Http服務器實現文件的上傳和下載,現在我回顧一下在上一章節中提到的一些內容,之前我已經提到過文件的下載,在文件的下載中也提到了文件的續下載只需要在響應頭中填寫C