主頁 > 軟體設計 > cpp-http 庫的使用

cpp-http 庫的使用

2021-09-22 08:36:46 軟體設計

文章目錄

    • 前言
    • `cpp-http` 庫簡介
    • `cpp-http` 庫使用介紹
      • http 客戶端搭建步驟
      • http 服務端搭建步驟
    • `cpp-http` 庫示例
      • 服務端實作
      • 客戶端實作
  • 參考資料

前言

最近在做的一個專案需要使用到 HTTP 協議,在網上查了很久,也結合了之前學長做的專案,發現 cpp-http 庫使用挺多的,所以就邊學邊做筆記,順便分享出來(我覺得知識之所以叫知識,就是因為它能被記錄并能被傳播,為人所知,為人所識),

我準備把這個學習記錄做成一個系列文章,這個系列里面,我會介紹從 HTTP 協議誕生到目前的一些大概情況,然后會簡單介紹一下目前 C/C++ 下面用的比較廣泛的 HTTP 庫,之后就是講解 cpp-http 庫的簡單使用、 cpp-http 庫的實作,最后如果時間允許的話可以自己手碼一個 C 語言的 http 用來作總結,

反正 flag 在這里先立下了,這篇文章是這個系列的第一篇,但是并不是按順序來的第一篇,這里講的是 cpp-http 庫的簡單使用,按順序來看的話應該是系列里面的第三篇或者第二篇,如果大家目前對 HTTP 協議基礎知識有需求的話還請移步其他博主的文章,之后我也會陸續把各個模塊補上(下一篇可能是 cpp-http 庫的實作部分),敬請大家期待,

另:本人目前是大學生,新人一枚,文章之中難免會有紕漏,還請大家多多包涵,不吝賜教,

cpp-http 庫簡介

  1. cpp-http 庫是什么?
    cpp-http 由是一位國外程式員 yhirose 在 github 上面開源的一個 C++ 專案,同時這個專案得到了世界各地程式員的支持,目前包括原作者在內共有 104 位貢獻者,擁有 5.7k Star 和 1.2k Fork,是目前使用較為廣泛的一個 C++ http庫之一,

  2. cpp-http 專案地址
    https://github.com/yhirose/cpp-httplib
    如果網路不好不能訪問 github 的話,這里是國內一位程式員搬運到 gitee 上面的專案,內容都是一樣的:
    https://gitee.com/zhangkt1995/cpp-httplib?_from=gitee_search

  3. 關于它的簡介,這里參考原作者的話:

    A C++11 single-file header-only cross platform HTTP/HTTPS library.

    It’s extremely easy to setup. Just include the httplib.h file in your code!

    NOTE: This is a multi-threaded ‘blocking’ HTTP library. If you are looking for a ‘non-blocking’ library, this is not the one that you want.

    翻譯過來就是:

    一個只有頭檔案的跨平臺 HTTP/HTTPS 庫,

    簡單易用,只需要包含頭檔案 httplib,h 即可,

    注意:這個庫是一個多執行緒阻塞式 Http 庫,如果您需要的是一個非阻塞式的庫,這個庫并不適合您,

cpp-http 庫使用介紹

網上大多數教程都只介紹了使用 cpp-http 庫的 GET 請求使用,沒有 POST 請求的(其實兩者使用一模一樣),在這里我也加上了 POST 請求的部分,

http 客戶端搭建步驟

  1. 組織http協議格式的請求資料
  2. 搭建tcp客戶端
  3. 發送組織好的http請求資料
  4. 等待服務端回應,接收回應資料
  5. 對回應資料的決議

http 服務端搭建步驟

  1. 搭建tcp服務端
  2. 等待接收客戶端發送的資料
  3. 按照 http 協議格式,對資料進行決議(格式按照: 請求方法 URL 協議版本\r\n 頭部\r\n 正文)
  4. 根據請求的資源路徑以及查詢字串以及正文,進行業務處理
  5. 組織http協議格式的回應,回傳給客戶端(協議版本 狀態碼 描述\r\n 頭部)

cpp-http 庫示例

這里我們先用個 demo 來看看 cpp-http 庫怎么使用:

首先先建立工程,目錄如下:

? tree ../http -L 1 
../http
├── client.cpp	# 在這里編輯客戶端的代碼
├── httplib.h	# 這是 cpp-http 庫的頭檔案,server和client都需要包含它
└── server.cpp # 在這里編輯服務端的代碼

0 directories, 5 files

其中 httplib.h 就是 cpp-http 庫的所有內容了,就是這一個頭檔案;server.cpp 是我們自己的服務端程式, client.cpp 是我們自己的客戶端程式,

服務端實作

  1. 代碼,相關的解釋都在注釋里面
#include <iostream>
#include "httplib.h"

using Request = httplib::Request;
using Response = httplib::Response;
using Server = httplib::Server;
using Params = httplib::Params;

// get 請求中對 "/go" 的處理
void get_go(const Request& req, Response& res)
{
    // 設定 "/go" 請求回傳的內容
    res.set_content("<html><h1>I'm the king of the world!</h1></html>", "text/html");

    std::cout << "Received a request of get [go]." << std::endl;
}

int main(int argc, char const *argv[])
{
    // 搭建服務端
    Server srv;

    // 這里注冊用于處理 get 請求的函式,當收到對應的get請求時,程式會執行對應的函式
    srv.Get("/go", get_go); // 可能相比 lambda 運算式,剛從 C 語言轉過來的同學更熟悉這種形式,這個get呼叫方式也更簡介易懂

    // 這里注冊的處理函式是 C++ 的 lambda 運算式,直接看成傳入了一個指標就行了
    srv.Get("/hi", [&](const Request& req, Response& res){
        // 設定 get "hi" 請求回傳的內容
        res.set_content("<html><h1>Hello world!</h1></html>", "text/html");

        std::cout << "Received a request of get [hi]." << std::endl;
    });
    
    srv.Get("/link", [&](const Request& req, Response& res){
        res.set_content("<html><h1 href=https://baike.baidu.com/item/%E8%A5%BF%E5%8D%8E%E5%A4%A7%E5%AD%A6%E6%9C%BA%E5%99%A8%E4%BA%BA%E8%B6%B3%E7%90%83%E5%8D%8F%E4%BC%9A/22274030>soccer robot</h1></html>", "text/html");

        std::cout << "Received a request of get [link]." << std::endl;
    });

    // POST 請求處理
    srv.Post("/get_info", [&](const Request& req, Response& res) {
        res.set_content("<html><h1>Go ahead!</h1></html>", "text/html");

        std::cout << "Received a request of POST [get_info]." << std::endl;
    });

    // 系結埠,啟動監聽
    srv.listen("0.0.0.0", 12345);
    
    return 0;
}

這里大家可能有三個疑問:

  • Server::Get()Server::Post() 注冊函式的實作機制,收到請到 GET 請求后是怎么執行對應函式的
  • 使用 Server::listen() 啟動埠的實作機制
  • lambda 運算式

其中前兩點我會在后面解釋,關于lambda運算式的部分可能之后會出相應的文章來介紹,在此之前還請各位移步其他關于 lambda 的文章進行學習,

  1. 編譯
    cpp-http 庫編譯時需要使用執行緒庫 pthread
    編譯時使用 g++ 直接編譯,使用 gcc 編譯會報錯(畢竟 gcc 是為 C 設計的)

編譯時使用命令:

g++ ./server.cpp -lpthread -o sever.out
  1. 執行
    執行服務端程式:
./server.out
  1. 驗證服務端:
  • 可以通過 curl 來查看服務端回傳的資料
# 示例如下
$ curl http://ip:port/source 
# 這里的 ip 是服務端運行所在電腦的ip,可以通過 `ip -a` 來查看
# port 就是我們在服務端里面指定監聽的埠
# source 是通過 http 請求的資源,在這里就是 /hi /link /go 那三個,

在這里插入圖片描述
最后一行 使用 curl http://0.0.0.0:12345/get_info 時沒有回傳,并且服務器端也沒有接收到資料,說明 curl 直接發送 /get_info 并不能用于提交 POST 請求,怎么使用 curl 提交 POST 請求等我之后有時間了再看看,

	? curl http://0.0.0.0:12345/hi  # 這里是請求 /link 資源需要的命令
	<html><h1>Hello world!</h1></html>% # 這里是服務器回應的資料
	
	? curl http://0.0.0.0:12345/link
	<html><h1 href=https://baike.baidu.com/item/%E8%A5%BF%E5%8D%8E%E5%A4%A7%E5%AD%A6%E6%9C%BA%E5%99%A8%E4%BA%BA%E8%B6%B3%E7%90%83%E5%8D%8F%E4%BC%9A/22274030>soccer robot</h1></html>%

	? curl http://0.0.0.0:12345/go
	<html><h1>I'm the king of the world!</h1></html>%
  
  ? curl http://0.0.0.0:12345/get_info
  • 也可以通過瀏覽器來查看資料:

通過在瀏覽器地址欄輸入相應的地址來驗證 http 服務端,直接在瀏覽器地址欄填入鏈接就好了:
例如我在瀏覽器輸入如下地址

http://http://0.0.0.0:12345/hi

結果如圖:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2HlVbtJ5-1632225570442)(:/7d334fd2bb5546a6ae90e6e14f0938a5)]

  • 如果一切正常的話,服務端的輸出是這樣:

? ./server.out
Received a request of get [link].
Received a request of get [link].
Received a request of get [hi].
Received a request of get [link].
Received a request of get [link].
Received a request of get [go].
Received a request of get [hi].

客戶端實作

  1. 代碼
#include <iostream>
#include <string>
#include "httplib.h"

using Client = httplib::Client;
using string = std::string;

int main(int argc, char const *argv[])
{
    if (argc < 3) {
        std::cout << "Please input server ip and port" << std::endl;

        return 0;
    }

    string source; // 用于存盤資源名稱

    // 創建客戶端
    // argv[1] 是從命令列傳入的 ip
    // argv[2] 是從命令列傳入的 port
    Client cli(argv[1], atoi(argv[2]));

    // 這里是一個死回圈,用于選擇需要讀取的資源
    while (true) {
        std::cout << "Please input the source you want" 
                  << "(Or use <CTRL + Z> to exit):" 
                  << std::endl;

        // 從命令列獲取下一步需要獲取的資源名稱
        std::getline(std::cin, source, '\n');
        // std::cout << source << std::endl;

        // GET、POST 請求的回傳值
        std::shared_ptr<httplib::Response> res;

        if (source == "/get_info") {
            // POST 請求
            res = cli.Post(source.c_str()); 
        } else {
            // GET 請求
            res = cli.Get(source.c_str());
        }
        
        if (res) {
            if (res->status == 200) { // 獲取對應資源成功,輸出獲取到的資訊
                std::cout << "Recved response from server: \n\r"
                          << res->body 
                          << "\n\r" << std::endl;
            } else{ // 獲取資源失敗,輸出 http 狀態碼
                std::cout << "Request error: " << res->status 
                          << "\n\r" << std::endl;
            }
        } else { // 發送失敗(多半是配置問題)
            std::cout << "Request GET failed.\n\r" << std::endl;
        }

        sleep(1); // 執行緒休眠
    }
    
    return 0;
}
  1. 編譯
  • 編譯命令和 編譯 server.cpp 是一樣的,不過引數要改成 client.cpp
g++ ./client.cpp -lpthread -o client.out
  • 編譯完成后的目錄:
? tree -L 1 ../http 
../http
├── client.cpp
├── client.out
├── httplib.h
├── server
├── server.cpp
└── server.out

0 directories, 6 files
  1. 執行
  • 執行服務端和客戶端程式:
./server.out
  • 執行客戶端程式:
? ./client.out 0.0.0.0 12345
Please input the source you want(Or use <CTRL + Z> to exit):
/go
Recved response from server: 
<html><h1>I'm the king of the world!</h1></html>

Please input the source you want(Or use <CTRL + Z> to exit):
/link
Recved response from server: 
<html><h1 href=https://baike.baidu.com/item/%E8%A5%BF%E5%8D%8E%E5%A4%A7%E5%AD%A6%E6%9C%BA%E5%99%A8%E4%BA%BA%E8%B6%B3%E7%90%83%E5%8D%8F%E4%BC%9A/22274030>soccer robot</h1></html>

Please input the source you want(Or use <CTRL + Z> to exit):
/hi
Recved response from server: 
<html><h1>Hello world!</h1></html>

Please input the source you want(Or use <CTRL + Z> to exit):
  • 程式執行結果:
    在這里插入圖片描述

參考資料

  1. 如何用chrome瀏覽器發送POST請求:https://www.hm1006.cn/archives/chromepost
  2. 【專案】cpp-httplib庫的原理:https://blog.csdn.net/weixin_43939593/article/details/104263043
  3. 推薦一個比較好用的c++版本http協議庫-cpp-httplib:https://blog.csdn.net/wuquan_1230/article/details/117690607

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/301924.html

標籤:其他

上一篇:使用Nmap檢測漏洞

下一篇:作業系統學習筆記:作業系統基礎知識

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more