C++中實(shí)現(xiàn)WebSocket通信的兩種方法:libwebsockets庫(kù)、Boost.Beast?庫(kù)
概述
WebSocket協(xié)議是現(xiàn)代Web開發(fā)中不可或缺的一部分,它允許客戶端和服務(wù)器之間建立持久的連接,實(shí)現(xiàn)雙向?qū)崟r(shí)通信。與傳統(tǒng)的HTTP請(qǐng)求不同,WebSocket提供了一種全雙工的通信通道,使得數(shù)據(jù)可以在任意方向上傳輸,而無需等待對(duì)方請(qǐng)求或者應(yīng)答。
WebSocket是在HTML5中引入的一種新協(xié)議,旨在替代輪詢等技術(shù)來實(shí)現(xiàn)客戶端與服務(wù)器間的實(shí)時(shí)交互。它通過HTTP或HTTPS協(xié)議發(fā)起一個(gè)特殊的請(qǐng)求,一旦連接建立成功,就可以繞過HTTP協(xié)議直接進(jìn)行數(shù)據(jù)交換。其主要的工作流程可以參考下圖。
握手階段:客戶端發(fā)起一個(gè)HTTP請(qǐng)求,這個(gè)請(qǐng)求與普通的GET請(qǐng)求差不多。但它包含了一些額外的頭字段,比如:Upgrade、Connection、Sec-WebSocket-Key等,表明客戶端希望將現(xiàn)有的TCP連接升級(jí)為WebSocket連接。
連接建立:如果服務(wù)器同意升級(jí),則會(huì)返回一個(gè)狀態(tài)碼為101(Switching Protocols)的響應(yīng),并且同樣帶有Upgrade、Connection等頭字段。
數(shù)據(jù)傳輸:一旦握手完成,雙方就可以開始發(fā)送和接收數(shù)據(jù)幀。每個(gè)幀都包含一個(gè)頭部,指示數(shù)據(jù)是否為二進(jìn)制還是文本形式,以及是否為消息的一部分等信息。
C++中WebSocket庫(kù)
cpp-websocket:這是一個(gè)C++編寫的WebSocket庫(kù),提供了簡(jiǎn)單易用的API,支持WebSocket握手、消息傳輸和關(guān)閉連接等功能。cpp-websocket的代碼量相對(duì)較小,易于集成到項(xiàng)目中。
asio_websocket:基于Boost.Asio庫(kù)的一個(gè)C++ WebSocket庫(kù)。Boost.Asio是一個(gè)廣泛使用的C++網(wǎng)絡(luò)編程庫(kù),提供了異步I/O操作、事件驅(qū)動(dòng)編程等功能。asio_websocket繼承了Boost.Asio的高性能和靈活性,同時(shí)提供了WebSocket協(xié)議的實(shí)現(xiàn)1。
websockets++:這是一個(gè)C++11編寫的輕量級(jí)WebSocket庫(kù),支持WebSocket握手、消息傳輸和關(guān)閉連接等功能。websockets++提供了簡(jiǎn)潔的API和豐富的文檔,方便開發(fā)者學(xué)習(xí)和使用。
websocketpp:這是一個(gè)功能豐富的C++ WebSocket庫(kù),支持多種WebSocket協(xié)議版本,適用于復(fù)雜的WebSocket通信需求。websocketpp是跨平臺(tái)的開源庫(kù),支持事件驅(qū)動(dòng)接口和靈活的依賴管理。
libwebsockets:這是一個(gè)跨平臺(tái)的C語言庫(kù),支持C++綁定,提供了靈活的WebSocket通信解決方案。libwebsockets適合對(duì)性能有高要求的場(chǎng)景。
uWebSockets:這是一個(gè)簡(jiǎn)單、高效且輕量級(jí)的WebSocket和HTTP實(shí)現(xiàn),底層依賴于libuv庫(kù)。uWebSockets非常適合需要處理大量并發(fā)連接的場(chǎng)景,盡管它在某些平臺(tái)或環(huán)境中的穩(wěn)定性和成熟度可能不如其他庫(kù)。
Boost.Beast:這是一個(gè)基于Boost庫(kù)的WebSocket庫(kù),提供了高性能和易用的API來實(shí)現(xiàn)WebSocket通信。Boost.Beast適用于需要高性能和易用性的場(chǎng)景。
Simple-WebSocket-Server:這是一個(gè)輕量級(jí)的WebSocket庫(kù),適用于簡(jiǎn)單的WebSocket通信需求。
libwebsockets庫(kù)
libwebsockets是一個(gè)開源的C語言庫(kù),用于實(shí)現(xiàn)WebSocket和HTTP服務(wù)器及客戶端。它非常靈活,支持多種協(xié)議,適合用于開發(fā)高性能的應(yīng)用程序和服務(wù)。libwebsockets的主要功能如下:
1、WebSocket服務(wù)器和客戶端:支持WebSocket協(xié)議的完整實(shí)現(xiàn),可以創(chuàng)建WebSocket服務(wù)器和客戶端。
2、HTTP服務(wù)器:支持HTTP/1.x和HTTP/2協(xié)議,可以創(chuàng)建高性能的HTTP服務(wù)器。
3、TLS/SSL支持:支持使用OpenSSL進(jìn)行加密,確保通信的安全性。
4、事件驅(qū)動(dòng)模型:采用非阻塞的I/O模型,適合處理大量并發(fā)連接。
5、數(shù)據(jù)壓縮:支持使用zlib進(jìn)行數(shù)據(jù)壓縮,減少帶寬消耗。
6、自定義協(xié)議:允許用戶定義自己的協(xié)議,而不僅僅限于WebSocket和HTTP。
使用libwebsockets庫(kù)開發(fā)WebSocket客戶端主要有六步,其工作流程可以參考下圖。
1、初始化庫(kù)和上下文。首先需要初始化libwebsockets庫(kù),使用lws_create_context函數(shù)創(chuàng)建一個(gè)上下文對(duì)象,該對(duì)象包含了庫(kù)運(yùn)行所需的配置信息。
2、創(chuàng)建連接。使用lws_client_connect函數(shù)創(chuàng)建一個(gè)WebSocket連接到指定的服務(wù)器,服務(wù)器的URL由調(diào)用方給出。
3、注冊(cè)回調(diào)函數(shù)。為了處理連接的不同階段,我們需要注冊(cè)回調(diào)函數(shù)。這些回調(diào)函數(shù)會(huì)在特定的事件發(fā)生時(shí)被調(diào)用,比如:連接建立、連接斷開、數(shù)據(jù)接收等。一般在lws_context_creation_info結(jié)構(gòu)體的callbacks字段中,可以指定回調(diào)函數(shù)。
4、發(fā)送和接收數(shù)據(jù)。一旦連接建立,我們便可以開始發(fā)送和接收數(shù)據(jù)。發(fā)送數(shù)據(jù)通常在LWS_CALLBACK_CLIENT_WRITEABLE回調(diào)中進(jìn)行,使用lws_send或lws_write函數(shù),而接收數(shù)據(jù)則在LWS_CALLBACK_CLIENT_RECEIVE回調(diào)中進(jìn)行。
5、處理事件循環(huán)。libwebsockets庫(kù)使用事件循環(huán)來處理網(wǎng)絡(luò)I/O操作,我們需要在一個(gè)無限循環(huán)中調(diào)用lws_service函數(shù)來處理事件。
6、清理資源。當(dāng)不再需要連接時(shí),應(yīng)該釋放所有由libwebsockets分配的資源,通常通過調(diào)用lws_context_destroy函數(shù)來銷毀上下文。
根據(jù)上面的工作流程,我們不難寫出WebSocket客戶端的示例代碼,具體如下。
#include <libwebsockets.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define WEB_SOCKET_MSG "Hello From Hope Wisdom" static lws_context *s_pContext = nullptr; // WebSocket客戶端回調(diào)函數(shù) static int OnCallbackWebSocket(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { switch(reason) { case LWS_CALLBACK_CLIENT_ESTABLISHED: // 連接已建立 printf("Connected!\n"); break; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: // 連接錯(cuò)誤 printf("Connection error: %s\n", (char *)in); break; case LWS_CALLBACK_CLIENT_CLOSED: // 連接關(guān)閉 printf("Disconnected.\n"); break; case LWS_CALLBACK_CLIENT_RECEIVE: // 接收數(shù)據(jù) printf("Received: %.*s\n", (int)len, (const char *)in); break; case LWS_CALLBACK_CLIENT_WRITEABLE: // 當(dāng)連接可寫時(shí),可以發(fā)送數(shù)據(jù) if (lws_send(wsi, WEB_SOCKET_MSG, strlen(WEB_SOCKET_MSG), LWS_SEND_TEXT) < 0) { printf("Send failed!\n"); } break; default: break; } return 0; } static int init_lws() { struct lws_context_creation_info info; lws_zeroize(&info, sizeof(info)); info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_VALIDATE_UTF8; // 設(shè)置回調(diào)函數(shù) info.callbacks = &OnCallbackWebSocket; // 設(shè)置端口(客戶端不需要監(jiān)聽端口) info.port = LWS_NO_LISTEN; info.name = "Client"; // 創(chuàng)建上下文 s_pContext = lws_create_context(&info); if (!s_pContext) { printf("Failed to create context\n"); return -1; } return 0; } static int connect_to_server(const char *uri) { struct lws *wsi = nullptr; wsi = lws_client_connect(s_pContext, uri, nullptr, LWS_CLIENT_CONNECT); if (!wsi) { printf("Failed to connect to %s\n", uri); return -1; } return 0; } int main(int argc, char **argv) { if (argc < 2) { printf("Usage: %s <websocket-uri>\n", argv[0]); return -1; } // 初始化libwebsockets庫(kù) if (init_lws() < 0) { return -1; } // 連接到WebSocket服務(wù)器 if (connect_to_server(argv[1]) < 0) { return -1; } // 主事件循環(huán) while (lws_service(s_pContext, 0)) { // 自動(dòng)處理連接的讀寫 } // 釋放資源 lws_context_destroy(s_pContext); return 0; }
Boost.Beast擴(kuò)展
Boost.Beast,可簡(jiǎn)稱為Beast,是Boost庫(kù)中的一個(gè)子項(xiàng)目。它是一個(gè)現(xiàn)代C++網(wǎng)絡(luò)庫(kù),主要用于構(gòu)建高性能的網(wǎng)絡(luò)應(yīng)用程序和服務(wù)。Beast是專門為C++11及更高版本設(shè)計(jì)的,它利用了現(xiàn)代C++語言的特性,比如:移動(dòng)語義、智能指針等,以提高軟件整體性能。
Beast的主要組件包括:基礎(chǔ)的網(wǎng)絡(luò)抽象(比如:Stream、Buffer)、HTTP(包括:HTTP/1.x、HTTP/2)、WebSockets等。其主要特點(diǎn)如下。
1、基于Boost.Asio。Beast是基于Boost.Asio的高級(jí)網(wǎng)絡(luò)庫(kù),因此它可以無縫集成到任何使用Boost.Asio的項(xiàng)目中。Beast提供了異步IO模型,允許非阻塞的操作,這對(duì)于構(gòu)建高并發(fā)的網(wǎng)絡(luò)服務(wù)非常重要。
2、高性能。設(shè)計(jì)用于高性能的應(yīng)用場(chǎng)景,支持高效的內(nèi)存管理,避免不必要的內(nèi)存拷貝。提供了零拷貝機(jī)制,即在傳輸數(shù)據(jù)時(shí)不進(jìn)行內(nèi)存復(fù)制,而是直接使用原始數(shù)據(jù)緩沖區(qū)。
3、易于使用。提供了簡(jiǎn)潔的API,使得編寫網(wǎng)絡(luò)應(yīng)用程序變得更加直觀和容易。支持錯(cuò)誤處理機(jī)制,使得捕獲和處理網(wǎng)絡(luò)錯(cuò)誤變得更加容易。
4、協(xié)議支持。支持多種網(wǎng)絡(luò)協(xié)議,包括:HTTP/1.x、HTTP/2、WebSockets等。另外,還提供了HTTP和WebSocket的客戶端和服務(wù)器實(shí)現(xiàn)。
5、跨平臺(tái)。Beast可以在多個(gè)操作系統(tǒng)上運(yùn)行,包括:Windows、Linux、MacOS等。它具有良好的跨平臺(tái)兼容性,使得開發(fā)者可以編寫一次代碼并在不同平臺(tái)上運(yùn)行。
使用Beast庫(kù)編寫WebSocket客戶端比較簡(jiǎn)單,示例代碼如下。
#include <boost/beast.hpp> #include <boost/asio.hpp> #include <iostream> #include <string> using namespace std; namespace beast = boost::beast; namespace http = beast::http; namespace net = boost::asio; using tcp = net::ip::tcp; int main() { try { // 創(chuàng)建I/O上下文和解析器 net::io_context ioc; tcp::resolver resolver(ioc); // 解析服務(wù)器地址和端口 auto endpoints = resolver.resolve("echo.websocket.org", "80"); // 創(chuàng)建并連接socket tcp::socket socket(ioc); beast::get_lowest_layer(socket).connect(endpoints); // 設(shè)置HTTP請(qǐng)求 http::request<http::string_body> req{http::verb::get, "/", 11}; req.set(http::field::host, "echo.websocket.org"); req.set(http::field::upgrade, "websocket"); req.set(http::field::connection, "Upgrade"); // 隨機(jī)的Base64編碼的WebSocket密鑰 req.set(http::field::sec_websocket_key, "dGhlIHNhbXBsZSBub25Nl29rZXk="); req.set(http::field::sec_websocket_version, "13"); // 使用websocket::stream進(jìn)行握手 websocket::stream<tcp::socket> ws{ioc}; ws.assign(std::move(socket)); // 發(fā)送HTTP升級(jí)請(qǐng)求并接收響應(yīng)來完成握手 http::response<http::string_body> res; ws.handshake(req, res); // 發(fā)送消息到服務(wù)器 beast::error_code ec; ws.write(net::buffer("Hello, Hope Wisdom"), ec); // 接收消息 while (true) { beast::flat_buffer receive_buffer; websocket::opcode op; ws.read(op, receive_buffer); ws.consume(receive_buffer.data().size()); if (op == websocket::opcode::close) { break; } cout << "Received: " << beast::buffers_to_string(receive_buffer.data()) << endl; } // 關(guān)閉連接 ws.close(websocket::close_code::normal); } catch (exception const& e) { cerr << "Error: " << e.what() << endl; } return 0; }
在上面的示例代碼中,我們首先創(chuàng)建了一個(gè)I/O上下文io_context和一個(gè)DNS解析器resolver,解析了服務(wù)器的地址和端口。接著,我們創(chuàng)建了一個(gè)TCP套接字,并使用解析結(jié)果中的端點(diǎn)列表連接到服務(wù)器。隨后,設(shè)置了HTTP請(qǐng)求,以發(fā)起WebSocket的握手請(qǐng)求,其中包括了必要的頭部信息,比如:Upgrade、Connection、Sec-WebSocket-Key、Sec-WebSocket-Version。這些頭部信息用于告知服務(wù)器希望將連接升級(jí)為WebSocket連接,并提供了握手所需的密鑰和版本號(hào)。
為了執(zhí)行WebSocket握手,我們創(chuàng)建了一個(gè)stream<socket>對(duì)象ws,并將之前的TCP套接字socket賦值給它。然后,調(diào)用ws.handshake函數(shù)來發(fā)送HTTP升級(jí)請(qǐng)求,并接收響應(yīng)以完成握手過程。
握手完成后,我們通過ws.write函數(shù)發(fā)送了一條文本消息到服務(wù)器。隨后,進(jìn)入一個(gè)無限循環(huán),不斷接收來自服務(wù)器的消息。每次接收到消息后,都會(huì)檢查是否為關(guān)閉幀。如果是,則退出循環(huán)。否則,打印接收到的消息。
最后,在退出循環(huán)時(shí),我們會(huì)釋放資源,關(guān)閉WebSocket連接和TCP套接字。
總結(jié)
C++中WebSocket庫(kù)主要有以下幾個(gè):cpp-websocket、asio_websocket、websockets++、websocketpp、libwebsockets、uWebSockets、Boost.Beast、Simple-WebSocket-Server,這篇文章使用libwebsockets庫(kù)、Boost.Beast庫(kù)來實(shí)現(xiàn)c++中的WebSocket通信。
到此這篇關(guān)于C++中實(shí)現(xiàn)WebSocket通信的兩種方法:libwebsockets庫(kù)、Boost.Beast庫(kù)的文章就介紹到這了,更多相關(guān)C++中WebSocket通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
opencv實(shí)現(xiàn)機(jī)器視覺檢測(cè)和計(jì)數(shù)的方法
在機(jī)器視覺中,有時(shí)需要對(duì)產(chǎn)品進(jìn)行檢測(cè)和計(jì)數(shù)。其難點(diǎn)無非是對(duì)于產(chǎn)品的圖像分割。本文就來介紹一下機(jī)器視覺檢測(cè)和計(jì)數(shù)的實(shí)現(xiàn),感興趣的可以參考一下2021-05-05C++實(shí)現(xiàn)簡(jiǎn)單的圖書管理系統(tǒng)
本文給大家分享的是使用C++實(shí)現(xiàn)簡(jiǎn)單的圖書管理系統(tǒng)的代碼,本系統(tǒng)采用了面向?qū)ο蟮某绦蛟O(shè)計(jì)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-08-08c++實(shí)現(xiàn)獲取當(dāng)前時(shí)間(精確至秒,毫秒和微妙)
這篇文章主要為大家詳細(xì)介紹了c++實(shí)現(xiàn)獲取當(dāng)前時(shí)間(可以精確至秒,毫秒和微妙)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2023-11-11關(guān)于C++靜態(tài)數(shù)據(jù)成員的實(shí)現(xiàn)講解
今天小編就為大家分享一篇關(guān)于關(guān)于C++靜態(tài)數(shù)據(jù)成員的實(shí)現(xiàn)講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12