網路程式設計: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,以避免系統阻塞
相關文章
- p2p網貸平臺設計簡析
- 網路通訊程式設計程式設計
- 網路協程程式設計程式設計
- Socket 程式設計 (網路篇)程式設計
- py網路工具程式設計程式設計
- Windows sdk程式設計筆記Windows程式設計筆記
- 計算機網路淺析(二)計算機網路
- 簡析網路競技遊戲匹配機制遊戲
- 從網路架構方面簡析迴圈神經網路RNN架構神經網路RNN
- PHP單一入口框架設計簡析PHP框架
- Python網路Socket程式設計Python程式設計
- python 網路篇(網路程式設計)Python程式設計
- BSN-DDC 基礎網路 DDC SDK 詳細設計(八):示例
- 【遊戲分析】異界鎖鏈設計簡析遊戲
- 淺析面向協議程式設計協議程式設計
- 網際網路竟能如此簡單!風變程式設計改變了我對網際網路的認知程式設計
- 網路程式設計-計算機網路三要素程式設計計算機網路
- 解析 | openshift原始碼簡析之pod網路配置(下)原始碼
- 網路安全論文–淺析計算機網路安全技術計算機網路
- 前端 JavaScript 程式設計風格淺析前端JavaScript程式設計
- BSN-DDC基礎網路DDC SDK詳細設計(七):資料解析
- 網站改造方向簡析網站
- 拜登政府《改善國家網路安全行政令》簡析
- 淺析平面設計與網頁設計的差異性網頁
- 簡析J2EE應用程式資料庫類設計模式 (轉)資料庫設計模式
- Go 語言的網路程式設計簡介Go程式設計
- IO程式設計和NIO程式設計簡介程式設計
- 計算機網路簡史計算機網路
- JavaScript SDK 設計指南JavaScript
- linux c網路網路程式設計面試題收集Linux程式設計面試題
- HUST-計算機網路實驗-socket程式設計計算機網路程式設計
- python網路-Socket之TCP程式設計(26)PythonTCP程式設計
- Java的網路功能與程式設計 一 (轉)Java程式設計
- Java中神經網路Triton GPU程式設計Java神經網路GPU程式設計
- Windows SDK程式設計之一 視窗示例程式 (轉)Windows程式設計
- 程式設計路漫漫程式設計
- 設計卷積神經網路CNN為什麼不是程式設計?卷積神經網路CNN程式設計
- windows程式設計簡介Windows程式設計