網路程式設計:C++REST SDK簡析
http_client程式碼示例
#include <iostream>
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif
#include <cpprest/http_client.h>
using namespace utility;
using namespace web::http;
using namespace web::http::client;
using namespace std::cerr;
using namespace std::endl;
#ifdef _WIN32 //根據平臺來定義tcout,確保多語言的文字能夠正確輸出
#define tcout std::wcout;
#else
#define tcout std::cout;
#endif
//從http_response中取出頭部的字串表示
auto get_headers(http_response resp) {
auto headers = resp.to_string();
auto end = headers.find("\r\n\r\n");
if (end != string_t::npos) {
headers.resize(end + 4);
}
return headers;
}
auto get_request(string_t uri) {
http_client client{ uri };
//用GET的方式發起一個客戶端請求
//並使用then方法串聯了兩個下一步動作
//http_client::request的返回值是pplx::task<http_response>.then是pplx::task類别範本的成員函式,引數是能接受其型別引數物件的函式物件,
//除了最後一個then,其他每個then裡都應該返回一個pplx::task,而task的內部型別,就是下一個then塊裡函式物件接受的引數型別。
auto request = client.request(methods::GET).then([](http_response resp) {
if (resp.status_code() != status_codes::OK) {
//不OK,顯示當前響應資訊
auto headers = get_headers(resp);
tcout << headers;
}
//進一步取出完整響應
return resp.extract_string();
}).then([](string_t str) {
//輸出到終端
tcout << str;
});
return request;
}
#ifdef _WIN32 //根據平臺定義合適的程式入口
int wmian(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
#ifdef _WIN32
_setmode(_fileno(stdout), _O_WTEXT);
#endif
if (argc != 2) {
cerr << "A URL is needed!\n";
return 1;
}
//等待請求及其關聯處理全部完成
try {
auto request = get_request(argv[1]);
request.wait();
}
//處理請求過程中產生的異常
catch (const std::exception& e){
cerr << "Error exception " << e.what() << endl;
return 1;
}
}
C++REST SDK是用來開發http客戶端和伺服器的現代非同步C++程式碼庫,支援http伺服器,http客戶端,非同步流,任務,JSON,URI,websocket客戶端。
非同步流
C++REST SDK實現了一套非同步流,能夠實現對檔案的非同步讀寫。
以下程式碼展示了把網路請求響應非同步儲存到檔案result.html中
#include <iostream>
#include <utility>
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif
#include <stddef.h>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
using namespace utility;
using namespace web::http;
using namespace web::http::client;
using namespace concurrency::streams;
using namespace std::cerr;
using namespace std::endl;
#ifdef _WIN32 //根據平臺來定義tcout,確保多語言的文字能夠正確輸出
#define tcout std::wcout;
#else
#define tcout std::cout;
#endif
//從http_response中取出頭部的字串表示
auto get_headers(http_response resp) {
auto headers = resp.to_string();
auto end = headers.find("\r\n\r\n");
if (end != string_t::npos) {
headers.resize(end + 4);
}
return headers;
}
auto get_request(string_t uri) {
http_client client{ uri };
//用GET的方式發起一個客戶端請求
//並使用then方法串聯了兩個下一步動作
//http_client::request的返回值是pplx::task<http_response>.then是pplx::task類别範本的成員函式,引數是能接受其型別引數物件的函式物件,
//除了最後一個then,其他每個then裡都應該返回一個pplx::task,而task的內部型別,就是下一個then塊裡函式物件接受的引數型別。
auto request = client.request(methods::GET)
.then([](http_response resp) {
if (resp.status_code() == status_codes::OK) {
//正常的話
tcout << U("Saving ...\n");
ostream fs;
fstream::open_ostream(
U("result.html"), std::ios_base::out | std::ios_base::trunc
).then([&fs, resp](ostream os) {
fs = os;
//讀取網頁內容到流
return resp.body().read_to_end(fs.streambuf());
}).then([&fs](size_t size) {
fs.close();
tcout << size << U(" bytes saved\n");
}).wait();
}
else {
//否則顯示當前響應資訊
auto headers = get_headers(resp);
tcout << headers;
tcout << resp.extract_string().get();
}
});
return request;
}
#ifdef _WIN32 //根據平臺定義合適的程式入口
int wmian(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
#ifdef _WIN32
_setmode(_fileno(stdout), _O_WTEXT);
#endif
if (argc != 2) {
cerr << "A URL is needed!\n";
return 1;
}
//等待請求及其關聯處理全部完成
try {
auto request = get_request(argv[1]);
request.wait();
}
//處理請求過程中產生的異常
catch (const std::exception& e){
cerr << "Error exception " << e.what() << endl;
return 1;
}
}
C++REST SDK的物件大部分都是基於shared_ptr實現的,因而可以輕鬆大膽的進行復制
JSON支援
C++REST SDK對JSON有很好的支援,JSON的基本型別有空值型別,布林型別,數字型別和字串型別,複合型別是陣列(array)和物件(object)
在C++REST SDK裡,核心型別是web::json::value
C++REST SDK裡的http_request 和http_response對JSON有原生支援,如可以使用extract_json成員函式來非同步提取http請求或響應體中的JSON內容
http伺服器
C++ REST SDK的http_listener會通過呼叫Boost.Asio和作業系統的底層介面(IOCP,epoll)來完成功能,向使用者隱藏這些細節,提供一個簡單的程式設計介面
//簡單rest伺服器示例程式碼,處理sayHi請求
#include <exception>
#include <iostream>
#include <map>
#include <string>
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif
#include <cpprest/http_listener.h>
#include <cpprest/json.h>
using namespace std;
using namespace utility;
using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;
#ifdef _WIN32
#define tcout std::wcout;
#else
#define tcout std::cout;
#endif
void handle_get(http_request req) {
//http_request::request_uri函式返回的是uri的引用,因而用auto&來接收
auto& uri = req.request_uri();
if (uri.path() != U("/sayHi")) {
req.reply(status_codes::NotFound);
return;
}
tcout << uri::decode(uri.query()) << endl;
auto query = uri::split_query(uri.query());
auto it = query.find(U("name"));
if (it == query.end()) {
req.reply(status_codes::BadRequest, U("Missing query info"));
return;
}
//http_request::reply的第二個引數是json::value型別,這會讓HTTP的Content-Type自動設定成 application/json
auto answer = json::value::object(true);
answer[U("msg")] = json::value(string_t(U("Hi, ")) + uri::decode(it->second) + U("!"));
req.reply(status_codes::OK, answer);
}
int main() {
#ifdef _WIN32
_setmode(_fileno(stdout), _O_WTEXT);
#endif
http_listener listener(U("http://127.0.0.1:8080/"));
listener.support(methods::GET, handle_get);
try {
listener.open().wait();
tcout << "Listener. Press Enter to exit.\n";
string line;
getline(cin, line);
listener.close().wait();
}
catch (const exception& e) {
cerr << e.what() << endl;
return 1;
}
}
C++REST SDK使用非同步的程式設計模式,使得寫不阻塞的程式碼變得很容易,底層它是用一個執行緒池實現的,預設會開啟40個執行緒,如果使用完了,會導致系統阻塞,執行緒數量程式碼中可控
//設定執行緒池大小為10
#include <pplx/threadpool.h>
crossplat::threadpool::initialize_with_threads(10);
C++REST伺服器應當增加執行緒池大小,並且對併發數量進行統計,在併發數接近執行緒池大小時拒絕新的連線,一般可返回status_codes::ServiceUnavailable,以避免系統阻塞
相關文章
- 網路通訊程式設計程式設計
- py網路工具程式設計程式設計
- Windows sdk程式設計筆記Windows程式設計筆記
- python 網路篇(網路程式設計)Python程式設計
- 計算機網路淺析(二)計算機網路
- 從網路架構方面簡析迴圈神經網路RNN架構神經網路RNN
- BSN-DDC 基礎網路 DDC SDK 詳細設計(八):示例
- 網際網路竟能如此簡單!風變程式設計改變了我對網際網路的認知程式設計
- 網路程式設計-計算機網路三要素程式設計計算機網路
- 簡析網路競技遊戲匹配機制遊戲
- 淺析面向協議程式設計協議程式設計
- 解析 | openshift原始碼簡析之pod網路配置(下)原始碼
- python網路-Socket之TCP程式設計(26)PythonTCP程式設計
- BSN-DDC基礎網路DDC SDK詳細設計(七):資料解析
- 【遊戲分析】異界鎖鏈設計簡析遊戲
- linux c網路網路程式設計面試題收集Linux程式設計面試題
- HUST-計算機網路實驗-socket程式設計計算機網路程式設計
- 程式設計路漫漫程式設計
- Java中神經網路Triton GPU程式設計Java神經網路GPU程式設計
- 計算機網路簡史計算機網路
- 網站改造方向簡析網站
- 設計卷積神經網路CNN為什麼不是程式設計?卷積神經網路CNN程式設計
- shell 程式設計簡記程式設計
- 【go網路程式設計】-HTTP程式設計Go程式設計HTTP
- Java 網路程式設計(TCP程式設計 和 UDP程式設計)Java程式設計TCPUDP
- 拜登政府《改善國家網路安全行政令》簡析
- 最簡單的C程式設計--順序程式設計C程式程式設計
- 網路安全程式設計 windowns防火牆培訓程式設計防火牆
- Java網路程式設計與NIO詳解8:淺析mmap和Direct BufferJava程式設計
- 【Linux網路程式設計】網路程式設計常見概念Linux程式設計
- 程式設計和網路程式設計入門程式設計
- JAVA網路程式設計(2)TCP程式設計Java程式設計TCP
- 淺析iOS-MAS&鏈式程式設計思想iOS程式設計
- 如何設計“.NET研究”一個簡結的移動網際網路站
- 網路程式設計程式設計
- Matlab程式設計之——卷積神經網路CNN程式碼解析Matlab程式設計卷積神經網路CNN
- 程式設計師程式設計時的簡單方法與技巧程式設計師
- 風變程式設計,讓程式設計學習更簡單!程式設計