【websocket】安裝與使用

websocket安裝與使用

  • 1. 介紹
  • 2. 安裝
  • 3. websocketpp常用接口
  • 4. Websocketpp使用
    • 4.1 服務端
    • 4.2 客戶端

1. 介紹

WebSocket 是從 HTML5 開始支持的一種網頁端和服務端保持長連接的 消息推送機制。

  • 傳統的 web 程序都是屬于 “一問一答” 的形式,即客戶端給服務器發送了一個
    HTTP 請求,服務器給客戶端返回一個 HTTP 響應。這種情況下服務器是屬于被動的一方,如果客戶端不主動發起請求服務器就無法主動給客戶端響應
  • 像網頁即時聊天這樣的程序非常依賴 “消息推送” 的,即需要服務器主動推動消息到客戶端。如果只是使用原生的 HTTP 協議,要想實現消息推送一般需要通過 “輪詢” 的方式實現, 而輪詢的成本比較高并且也不能及時的獲取到消息的響應。

基于上述兩個問題, 就產生了 WebSocket 協議。WebSocket 更接近于 TCP 這種級別的通信方式,一旦連接建立完成客戶端或者服務器都可以主動的向對方發送數據。

原理解析

WebSocket 協議本質上是一個基于 TCP 的協議。為了建立一個 WebSocket 連接,客戶端瀏覽器首先要向服務器發起一個 HTTP 請求,這個請求和通常的 HTTP 請求不同,包含了一些附加頭信息,通過這個附加頭信息完成握手過程并升級協議的過程。

在這里插入圖片描述

具體協議升級的過程如下:

在這里插入圖片描述

報文格式

在這里插入圖片描述

報文字段比較多,我們重點關注這幾個字段:

  • FIN: WebSocket 傳輸數據以消息為概念單位,一個消息有可能由一個或多個幀組成,FIN 字段為 1 表示末尾幀。

  • RSV1~3:保留字段,只在擴展時使用,若未啟用擴展則應置 1,若收到不全為 0的數據幀,且未協商擴展則立即終止連接。

  • opcode: 標志當前數據幀的類型

    • 0x0: 表示這是個延續幀,當 opcode 為 0 表示本次數據傳輸采用了數據分片,當前收到的幀為其中一個分片
    • 0x1: 表示這是文本幀
    • 0x2: 表示這是二進制幀
    • 0x3-0x7: 保留,暫未使用
    • 0x8: 表示連接斷開
    • 0x9: 表示 ping 幀
    • 0xa: 表示 pong 幀
    • 0xb-0xf: 保留,暫未使用
  • mask:表示 Payload 數據是否被編碼,若為 1 則必有 Mask-Key,用于解碼
    Payload 數據。僅客戶端發送給服務端的消息需要設置。

  • Payload length:數據載荷的長度,單位是字節, 有可能為 7 位、7+16 位、7+64位。假設 Payload length = x

    • x 為 0~126:數據的長度為 x 字節
    • x 為 126:后續 2 個字節代表一個 16 位的無符號整數,該無符號整數的值為數據的長度
    • x 為 127:后續 8 個字節代表一個 64 位的無符號整數(最高位為 0),該無符號整數的值為數據的長度
  • Mask-Key:當 mask 為 1 時存在,長度為 4 字節,解碼規則: DECODED[i] =
    ENCODED[i] ^ MASK[i % 4]

  • Payload data: 報文攜帶的載荷數據

Websocketpp 介紹

WebSocketpp 是一個跨平臺的開源(BSD 許可證)頭部專用 C++庫,它實現了
RFC6455(WebSocket 協議)和 RFC7692(WebSocketCompression Extensions)。它允許將 WebSocket 客戶端和服務器功能集成到 C++程序中。在最常見的配置中,全功能網絡 I/O 由 Asio 網絡庫提供。

WebSocketpp 的主要特性包括:

  • 事件驅動的接口
  • 支持 HTTP/HTTPS、WS/WSS、IPv6
  • 靈活的依賴管理 — Boost 庫/C++11 標準庫
  • 可移植性:Posix/Windows、32/64bit、Intel/ARM
  • 線程安全

WebSocketpp 同時支持 HTTP 和 Websocket 兩種網絡協議,可以該庫作為項目的依賴庫用來搭建 HTTP 和 WebSocket 服務器。

總結

websocket是一個應用層的tcp長連接協議。搭建一個websocket服務器其實就是搭建一個tcp服務器,只不過應用層使用websocket協議格式進行數據處理。

與此對比的就是httplib,它是一個短連接,只是讓我快速搭建一個Http服務器,讓我們重點關注業務處理。假如在一個項目中,不單單是 請求 - 響應 的業務處理,還包含了數據的主動推送,而這種消息數據的主動推送,是Http協議無法實現的。它只能是客戶端發起請求,然后服務器收到給一個響應。因此需要搭建一個長連接的服務器,用于服務端主動向客戶端推送數據。

選擇websocket協議的考慮:因為Http通信支持websocket協議的切換。
websocket通信框架的選擇:websocketpp 即支持websocket通信,也支持http通信。

2. 安裝

sudo apt-get install libboost-dev libboost-system-dev libwebsocketpp-dev

3. websocketpp常用接口

namespace websocketpp
{typedef lib::weak_ptr<void> connection_hdl;template <typename config>class endpoint : public config::socket_type{typedef lib::shared_ptr<lib::asio::steady_timer> timer_ptr;//通信連接類型typedef typename connection_type::ptr connection_ptr;typedef typename connection_type::message_ptr message_ptr;typedef lib::function<void(connection_hdl)> open_handler;typedef lib::function<void(connection_hdl)> close_handler;typedef lib::function<void(connection_hdl)> http_handler;typedef lib::function<void(connection_hdl, message_ptr)> message_handler;/* websocketpp::log::alevel::none 禁止打印所有日志*/void set_access_channels(log::level channels);   /*設置日志打印等級*/void clear_access_channels(log::level channels); /*清除指定等級的日志*//*設置指定事件的回調函數*/void set_open_handler(open_handler h);       /*websocket 握手成功回調處理函數*/void set_close_handler(close_handler h);     /*websocket 連接關閉回調處理函數*/void set_message_handler(message_handler h); /*websocket 消息回調處理函數*/void set_http_handler(http_handler h);       /*http 請求回調處理函數*//*發送數據接口*/void send(connection_hdl hdl, std::string &payload,frame::opcode::value op);void send(connection_hdl hdl, void *payload, size_t len,frame::opcode::value op);/*關閉連接接口*/void close(connection_hdl hdl, close::status::value code,std::string &reason);/*獲取 connection_hdl 對應連接的 connection_ptr*///weak_ptr無法對對象直接操作,必須要獲得對應的shared_ptr才能對對象進行對應操作connection_ptr get_con_from_hdl(connection_hdl hdl);/*websocketpp 基于 asio 框架實現,init_asio 用于初始化 asio 框架中的 io_service 調度器*/void init_asio();/*設置是否啟用地址重用*/void set_reuse_addr(bool value);/*設置 endpoint 的綁定監聽端口*/void listen(uint16_t port);/*對 io_service 對象的 run 接口封裝,用于啟動服務器*/std::size_t run();/*websocketpp 提供的定時器,以毫秒為單位*/timer_ptr set_timer(long duration, timer_handlercallback);};//繼承endpointtemplate <typename config>class server : public endpoint<connection<config>, config>{/*初始化并啟動服務端監聽連接的 accept 事件處理*/void start_accept();};template <typename config>class connection: public config::transport_type::transport_con_type,public config::connection_base{/*發送數據接口*/error_code send(std::string &payload, frame::opcode::value op = frame::opcode::text);/*獲取 http 請求頭部*/std::string const &get_request_header(std::string const &key)/*獲取請求正文*/std::string const &get_request_body();/*設置響應狀態碼*/void set_status(http::status_code::value code);/*設置 http 響應正文*/void set_body(std::string const &value);/*添加 http 響應頭部字段*/void append_header(std::string const &key, std::string const &val);/*獲取 http 請求對象*/request_type const &get_request();/*獲取 connection_ptr 對應的 connection_hdl */connection_hdl get_handle();};namespace http{namespace parser{class parser{std::string const &get_header(std::string const &key)std::string const &get_body() typedef std::map<std::string, std::string,utility::ci_less> header_list;header_list const &get_headers()}; class request : public parser{/*獲取請求方法*/std::string const &get_method()/*獲取請求 uri 接口*/std::string const &get_uri()};}};class message_buffer{/*獲取 websocket 請求中的 payload 數據類型*/frame::opcode::value get_opcode();/*獲取 websocket 中 payload 數據*/std::string const &get_payload();};namespace log{struct alevel{static level const none = 0x0;static level const connect = 0x1;static level const disconnect = 0x2;static level const control = 0x4;static level const frame_header = 0x8;static level const frame_payload = 0x10;static level const message_header = 0x20;static level const message_payload = 0x40;static level const endpoint = 0x80;static level const debug_handshake = 0x100;static level const debug_close = 0x200;static level const devel = 0x400;static level const app = 0x800;static level const http = 0x1000;static level const fail = 0x2000;static level const access_core = 0x00003003;static level const all = 0xffffffff;};}namespace http{namespace status_code{enum value{uninitialized = 0,continue_code = 100,switching_protocols = 101,ok = 200,created = 201,accepted = 202,non_authoritative_information = 203,no_content = 204,reset_content = 205,partial_content = 206,multiple_choices = 300,moved_permanently = 301,found = 302,see_other = 303,not_modified = 304,use_proxy = 305,temporary_redirect = 307,bad_request = 400,unauthorized = 401,payment_required = 402,forbidden = 403,not_found = 404,method_not_allowed = 405,not_acceptable = 406,proxy_authentication_required = 407,request_timeout = 408,conflict = 409,gone = 410,length_required = 411,precondition_failed = 412,request_entity_too_large = 413,request_uri_too_long = 414,unsupported_media_type = 415,request_range_not_satisfiable = 416,expectation_failed = 417,im_a_teapot = 418,upgrade_required = 426,precondition_required = 428,too_many_requests = 429,request_header_fields_too_large = 431,internal_server_error = 500,not_implemented = 501,bad_gateway = 502,service_unavailable = 503,gateway_timeout = 504,http_version_not_supported = 505,not_extended = 510,network_authentication_required = 511};}}namespace frame{namespace opcode{enum value{continuation = 0x0,text = 0x1,binary = 0x2,rsv3 = 0x3,rsv4 = 0x4,rsv5 = 0x5,rsv6 = 0x6,rsv7 = 0x7,close = 0x8,ping = 0x9,pong = 0xA,control_rsvb = 0xB,control_rsvc = 0xC,control_rsvd = 0xD,control_rsve = 0xE,control_rsvf = 0xF,};}}
}

4. Websocketpp使用

4.1 服務端

websocketpp搭建服務器流程:

  1. 定義server類型
  2. 實例化服務器對象
  3. 初始化日志輸出 – 關閉日志輸出
  4. 初始化asio框架
  5. 設置消息處理/連接握手成功/連接關閉回調函數/連接異常回調函數
  6. 啟動地址重用
  7. 設置監聽窗口
  8. 開始監聽
  9. 啟動服務器
#include<iostream>
#include<websocketpp/config/asio_no_tls.hpp>
#include<websocketpp/server.hpp>
#include<sstream>// 1. 定義server類型
typedef websocketpp::server<websocketpp::config::asio> websocketsvr;//websocket握手成功回調函數
void onopen(websocketpp::connection_hdl hdl)
{std::cout<<"websocket長連接建立成功"<<std::endl;
}//websocket 連接關閉回調處理函數
void onclose(websocketpp::connection_hdl hdl)
{std::cout<<"websocket關閉連接"<<std::endl;
}// websocket 連接異常的回調函數
void onfail(websocketsvr *server,websocketpp::connection_hdl hdl)
{std::cout<<"websocket連接異常"<<std::endl;
}//websocket 消息回調處理函數
void onmessage(websocketsvr* server,websocketpp::connection_hdl hdl,websocketsvr::message_ptr msg)
{//1. 獲取有效消息載荷數據,進行業務處理std::string body = msg->get_payload();std::cout<<"收到客戶端消息: "<<body<<std::endl;//2. 對客戶端進行響應//獲取通信連接auto conn = server->get_con_from_hdl(hdl);//發送數據conn->send(body + "服務器回復",websocketpp::frame::opcode::text);
}//http 請求回調處理函數
void onhttp(websocketsvr* server,websocketpp::connection_hdl hdl)
{auto conn = server->get_con_from_hdl(hdl);std::stringstream ss;ss << "<!doctype html><html><head>"<< "<title>hello websocket</title><body>"<< "<h1>hello websocketpp</h1>"<< "</body></head></html>";conn->set_body(ss.str());conn->set_status(websocketpp::http::status_code::ok);
}int main()
{// 2. 實例化服務器對象websocketsvr server;// 3. 初始化日志輸出 -- 關閉日志輸出// all 表示打印全部級別日志// none 表示什么日志都不打印server.set_access_channels(websocketpp::log::alevel::none);// 4. 初始化asio框架server.init_asio();// 5. 設置消息處理/連接握手成功/連接關閉回調函數/連接異常回調函數server.set_open_handler(onopen);server.set_close_handler(onclose);server.set_fail_handler(std::bind(onfail,&server,std::placeholders::_1));server.set_message_handler(std::bind(onmessage,&server,std::placeholders::_1,std::placeholders::_2));server.set_http_handler(std::bind(onhttp,&server,std::placeholders::_1));// 6. 啟動地址重用server.set_reuse_addr(true);// 7. 設置監聽窗口server.listen(8080);// 8. 開始監聽server.start_accept();// 9. 啟動服務器server.run();return 0;
}
server:server.ccg++ -o $@ $^ -std=c++17 -lpthread -lboost_system

4.2 客戶端

Http 客戶端

使用瀏覽器作為 http 客戶端即可, 訪問服務器的 8080 端口。

在這里插入圖片描述

WS 客戶端

HTML<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, 
initial-scale=1.0"><title>Test Websocket</title></head><body><input type="text" id="message"><button id="submit">提交</button><script>// 創建 websocket 實例// ws://124.223.54.148:8080// 類比 http// ws 表示 websocket 協議// 192.168.51.100 表示服務器地址// 8888 表示服務器綁定的端口let websocket = new WebSocket("ws://124.223.54.148:8080");// 處理連接打開的回調函數websocket.onopen = function() {console.log("連接建立");} // 處理收到消息的回調函數// 控制臺打印消息websocket.onmessage = function(e) {console.log("收到消息: " + e.data);} // 處理連接異常的回調函數websocket.onerror = function() {console.log("連接異常");} // 處理連接關閉的回調函數websocket.onclose = function() {console.log("連接關閉");} // 實現點擊按鈕后, 通過 websocket 實例 向服務器發送請求let input = document.querySelector('#message');let button = document.querySelector('#submit');button.onclick = function() {console.log("發送消息: " + input.value);websocket.send(input.value);} </script>
</body>
</html>

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/83252.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/83252.shtml
英文地址,請注明出處:http://en.pswp.cn/web/83252.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

微算法科技(NASDAQ:MLGO)基于信任的集成共識和灰狼優化(GWO)算法,搭建高信任水平的區塊鏈網絡

隨著數字化轉型的加速&#xff0c;區塊鏈技術作為去中心化、透明且不可篡改的數據存儲與交換平臺&#xff0c;正逐步滲透到金融、供應鏈管理、物聯網等多個領域&#xff0c;探索基于信任的集成共識機制&#xff0c;并結合先進的優化算法來提升區塊鏈網絡的信任水平&#xff0c;…

【項目實戰】通過多模態+LangGraph實現PPT生成助手

PPT自動生成系統 基于LangGraph的PPT自動生成系統&#xff0c;可以將Markdown文檔自動轉換為PPT演示文稿。 功能特點 Markdown解析&#xff1a;自動解析Markdown文檔結構PPT模板分析&#xff1a;分析PPT模板的布局和風格智能布局決策&#xff1a;匹配內容與合適的PPT布局自動…

貝葉斯優化+LSTM+時序預測=Nature子刊!

貝葉斯優化與LSTM的融合在時間序列預測領域取得了顯著成效&#xff0c;特別是在處理那些涉及眾多超參數調整的復雜問題時。 1.這種結合不僅極大提高了預測的精確度&#xff0c;還優化了模型訓練流程&#xff0c;提升了效率和成本效益。超參數優化的新篇章&#xff1a;LSTM因其…

AWSLambda之設置時區

目標 希望Lambda運行的時區是東八區。 解決 只需要設置lambda的環境變量TZ為東八區時區即可&#xff0c;即Asia/Shanghai。 參考 使用 Lambda 環境變量

RAG系統向量數據庫選型與Prompt Engineering魯棒性測試實踐

引言 在AI應用不斷落地的今天&#xff0c;RAG&#xff08;Retrieval-Augmented Generation&#xff0c;檢索增強生成&#xff09;和Prompt Engineering&#xff08;提示工程&#xff09;成為大模型工程師和測試工程師的核心武器。 一方面&#xff0c;RAG系統依賴強大的向量數據…

2.Socket 編程 UDP

1.UDP網絡編程 0.背景知識 自實現IP轉化 相關函數理解 IP相關理解 1. V2版本 - DictServer封裝版 實現一個簡單的英譯漢的網絡字典 Dict.hpp dictionary.txt InetAddr.hpp ? 在 InetAddr 中&#xff0c;重載一下方便對用戶是否是同一個進行比較 Log.hpp makefile Mutex.hpp…

數據可視化交互

目錄 【實驗目的】 【實驗原理】 【實驗環境】 【實驗步驟】 一、安裝 pyecharts 二、下載數據 三、實驗任務 實驗 1&#xff1a;AQI 橫向對比條形圖 代碼說明&#xff1a; 運行結果&#xff1a; 實驗 2&#xff1a;AQI 等級分布餅圖 實驗 3&#xff1a;多城市 AQI…

【MATLAB去噪算法】基于CEEMDAN聯合小波閾值去噪算法(第四期)

CEEMDAN聯合小波閾值去噪算法相關文獻 一、EMD 與 EEMD 的局限性 &#xff08;1&#xff09;EMD (經驗模態分解) 旨在自適應地將非線性、非平穩信號分解成一系列 本征模態函數 (IMFs)&#xff0c;這些 IMFs 從高頻到低頻排列。 核心問題&#xff1a;模態混合 (Mode Mixing) 同…

大話軟工筆記—架構模型

1. 架構模型1—拓撲圖 &#xff08;1&#xff09;拓撲圖概念 拓撲圖&#xff0c;將多個軟件系統用網絡圖連接起來的表達方式。 &#xff08;2&#xff09;拓撲圖分類 總線型結構 比較普遍采用的方式&#xff0c;將所有的系統接到一條總線上。 星狀結構 各個系統通過點到…

24-Oracle 23 ai ?Lock-Free Reservations?(無鎖列值保留)

數據庫領域為了解決ACID的平衡&#xff0c;嘗試了各種鎖、各種模式&#xff0c; 引擎技術特性、廠家實現方式各放異彩&#xff0c;被各種鎖折磨的小伙伴&#xff0c;是不是感同身受。 一、數據庫鎖 1. 鎖的類型與特點 ?全局鎖?&#xff1a;鎖定整個數據庫實例&#xff0c;備…

OpenPrompt 和直接對提示詞的嵌入向量進行訓練有什么區別

OpenPrompt 和直接對提示詞的嵌入向量進行訓練有什么區別 直接訓練提示詞嵌入向量的核心區別 您提到的代碼: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding

從零寫一個ALSA聲卡驅動學習(1)

前言&#xff1a; 本文檔描述了如何編寫 ALSA&#xff08;高級 Linux 音頻架構&#xff09;驅動程序。文檔主要聚焦于 PCI 聲卡的實現。對于其他類型的設備&#xff0c;可能會使用不同的 API。不過&#xff0c;至少 ALSA 的內核 API 是一致的&#xff0c;因此本文檔在編寫這些驅…

鏈結構與工作量證明7??:用 Go 實現比特幣的核心機制

鏈結構與工作量證明:用 Go 實現比特幣的核心機制 如果你用 Go 寫過區塊、算過哈希,也大致理解了非對稱加密、數據序列化這些“硬核知識”,那么恭喜你,現在我們終于可以把這些拼成一條完整的“區塊鏈”。 不過別急,這一節我們重點搞懂兩件事: 區塊之間是怎么連接成“鏈”…

深入理解 React 樣式方案

React 的樣式方案較多,在應用開發初期,開發者需要根據項目業務具體情況選擇對應樣式方案。React 樣式方案主要有: 1. 內聯樣式 2. module css 3. css in js 4. tailwind css 這些方案中,均有各自的優勢和缺點。 1. 方案優劣勢 1. 內聯樣式: 簡單直觀,適合動態樣式和…

YOLO電力物目標檢測訓練

最近需要進行電力物檢測相關的業務&#xff0c;因此制作了一個電力物數據集&#xff0c;使用YOLO目標檢測方法進行實驗&#xff0c;記錄實驗過程如下&#xff1a; 數據集標注 首先需要對電力物相關設備進行標注&#xff0c;這里我們選用labelme進行標注&#xff0c;使用無人機…

從阿里云域名解析異常事件看下域名解析過程

近日阿里云核心域名aliyuncs.com解析異常&#xff0c;涉及眾多依賴阿里云服務的網站和應用&#xff0c;故障從發現到修復耗時5個多小時。本文簡要分析下整個事件的過程&#xff0c;并分析域名解析的過程&#xff0c;了解根域名服務器在其中的作用&#xff0c;以了解。 1、aliyu…

應用分享 | 精準生成和時序控制!AWG在確定性三量子比特糾纏光子源中的應用

在量子技術飛速發展的今天&#xff0c;實現高效穩定的量子態操控是推動量子計算、量子通信等領域邁向實用化的關鍵。任意波形發生器&#xff08;AWG&#xff09;作為精準信號控制的核心設備&#xff0c;在量子實驗中發揮著不可或缺的作用。丹麥哥本哈根大學的研究團隊基于單個量…

基于規則的自然語言處理

基于規則的自然語言處理 規則方法形態還原&#xff08;針對英語、德語、法語等&#xff09;中文分詞切分歧義分詞方法歧義字段消歧方法分詞帶來的問題 詞性標注命名實體分類機器翻譯規則方法的問題 規則方法 以規則形式表示語言知識&#xff0c;強調人對語言知識的理性整理&am…

Vue Fragment vs React Fragment

文章目錄 前言&#x1f9e9; 一、概念對比&#xff1a;Vue Fragment vs React Fragment&#x1f4e6; 二、使用示例對比? Vue 3 中使用 Fragment? React 中使用 Fragment &#x1f50d; 三、差異解析1. **使用方式**2. **傳遞屬性&#xff08;如 key&#xff09;**3. **插槽系…

3D圖像渲染和threejs交互坐標系入門知識整理

1. Games101 b站上面就有&#xff0c;看到第9節課基本對于圖形渲染的原理和渲染過程有所了解。然后就可以使用openGL和GLSL。 點輸入->投影到二維&#xff08;生成三角形面&#xff09;->光柵化為像素->z-buffer深度緩存判斷層級->著色shading 2. openGL和GLSL 參…