文章目錄
- 前言
- `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 庫簡介
-
cpp-http庫是什么?
cpp-http由是一位國外程式員 yhirose 在 github 上面開源的一個 C++ 專案,同時這個專案得到了世界各地程式員的支持,目前包括原作者在內共有 104 位貢獻者,擁有 5.7kStar和 1.2kFork,是目前使用較為廣泛的一個 C++ http庫之一, -
cpp-http專案地址
https://github.com/yhirose/cpp-httplib
如果網路不好不能訪問 github 的話,這里是國內一位程式員搬運到 gitee 上面的專案,內容都是一樣的:
https://gitee.com/zhangkt1995/cpp-httplib?_from=gitee_search -
關于它的簡介,這里參考原作者的話:
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 客戶端搭建步驟
- 組織http協議格式的請求資料
- 搭建tcp客戶端
- 發送組織好的http請求資料
- 等待服務端回應,接收回應資料
- 對回應資料的決議
http 服務端搭建步驟
- 搭建tcp服務端
- 等待接收客戶端發送的資料
- 按照 http 協議格式,對資料進行決議(格式按照: 請求方法 URL 協議版本\r\n 頭部\r\n 正文)
- 根據請求的資源路徑以及查詢字串以及正文,進行業務處理
- 組織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 是我們自己的客戶端程式,
服務端實作
- 代碼,相關的解釋都在注釋里面
#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 的文章進行學習,
- 編譯
cpp-http庫編譯時需要使用執行緒庫pthread
編譯時使用g++直接編譯,使用gcc編譯會報錯(畢竟 gcc 是為 C 設計的)
編譯時使用命令:
g++ ./server.cpp -lpthread -o sever.out
- 執行
執行服務端程式:
./server.out
- 驗證服務端:
- 可以通過 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結果如圖:
- 如果一切正常的話,服務端的輸出是這樣:
? ./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].
客戶端實作
- 代碼
#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;
}
- 編譯
- 編譯命令和 編譯 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
- 執行
- 執行服務端和客戶端程式:
./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):
- 程式執行結果:

參考資料
- 如何用chrome瀏覽器發送POST請求:https://www.hm1006.cn/archives/chromepost
- 【專案】cpp-httplib庫的原理:https://blog.csdn.net/weixin_43939593/article/details/104263043
- 推薦一個比較好用的c++版本http協議庫-cpp-httplib:https://blog.csdn.net/wuquan_1230/article/details/117690607
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/301924.html
標籤:其他
上一篇:使用Nmap檢測漏洞


![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2HlVbtJ5-1632225570442)(:/7d334fd2bb5546a6ae90e6e14f0938a5)]](https://img.uj5u.com/2021/09/22/266669220834192.png)