c++ websocket客户端_你要的websocket都在这,收好不谢~~~
生活随笔
收集整理的這篇文章主要介紹了
c++ websocket客户端_你要的websocket都在这,收好不谢~~~
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
此號已經沉寂多時,似乎已經忘了上一次更新是什么時候了!這一次重拾舊愛,希望能夠一直保持下去,堅持寫作,快樂你我他今天的主題是websocket,相信搞研發的兄弟對websocket并不陌生,都2020了別說自己還不知道,那都TM騙人。咱們的目標只有一個,那就是要搞懂它,下面就開始擼起袖子盤它!!!
現狀
目前許多應用對數據實時更新要求很高。比如股票交易,數字資產交易,還有一些需要動態更新數據的大屏可視化應用等等。在HTML5面世前,動態實時更新數據的做法大多使用ajax定時輪詢,或者長輪詢來處理消息的實時推送。但是輪詢的做法效率相當低,這樣勢必會較大程度浪費服務器和帶寬資源,而我們接下來要講的WebSocket正是來解決該問題而出現的,它可以使得B/S架構的應用擁有像C/S架構一樣的實時通信能力websocket簡介
WebSocket 是 HTML5 新增的一種在單個 TCP 連接上進行全雙工通訊的協議。誕生于2008年,在2011年成為國際標準。現在新版的所有瀏覽器都已經支持,但一些舊版本的瀏覽器兼容性就不是很好了WebSocket的最大特點是:允許客戶端和服務器之間進行全雙工通信(即客戶端可以向服務端推送數據,服務端也可以主動向客戶端推送數據),以便任一方都可以通過建立的連接將數據推送到另一端,是真正的雙向平等對話,屬于服務器推送技術的一種WebSocket最新的協議是 13 RFC 6455websocket特性
了解HTTP協議的童鞋應該都知道HTTP協議有以下兩個突出的特性:其一:HTTP協議的通信只能由客戶端發起,它無法實現服務器主動向客戶端推送消息(單向請求)其二:HTTP協議是一種無狀態的應用層協議,它采用的是請求/響應模型,發送請求得到響應連接關閉(生命周期結束)。每次通信都需要攜帶驗證信息進行身份校驗(耗時、耗資源、效率低)WebSocket可以說是在HTTP的基礎上發明來的,改善了HTTP協議上面的兩個特性。WebSocket只需要建立一次HTTP連接,就可以一直保持連接狀態(如果兩端長時間都沒有通信也是會被關閉連接的 - 后面會講到),此時已經是從HTTP協議升級到了WebSocket協議,后面的通信都是基于websocket協議。這相比于輪詢方式的不停建立連接顯然效率要大大提高http和websocket對比:http和websocket協議及默認端口:
http和websocket都是建立在TCP協議之上:WebSocket如何工作
Web瀏覽器和服務器都必須支持 WebSocket 協議來建立和維護連接。由于 WebSocket 連接長期存在,與典型的 HTTP 連接不同,對服務器有重要的影響客戶端簡單示例:// 初始化實例var ws = new WebSocket("ws://echo.websocket.org");或者加密協議:var wss = new WebSocket("wss://echo.websocket.org");// 建立連接ws.onopen = function(evt) { console.log("連接建立成功,可以開始通信了..."); ws.send("Hello WebSocket!");};//?連接出錯ws.onerror = function(evt) {console.log("連接出錯 ...");}; // 消息監聽ws.onmessage = function(evt) {console.log( "收到服務端消息: " + evt.data); ws.close();};// 關閉連接ws.onclose = function(evt) {console.log("關閉連接 ...");};Websocket客戶端 API
1、WebSocket?構造函數WebSocket對象作為一個構造函數,用于新建WebSocket實例var webSocket = new WebSocket('ws://localhost:8080');var webSockets = new WebSocket('wss://localhost:8080');執行上面語句之后,客戶端就會與服務器進行連接2、webSocket.readyStatereadyState屬性,返回實例對象的當前狀態,共有四種:CONNECTING:值為0,表示正在連接。OPEN:值為1,表示連接成功,可以通信了。CLOSING:值為2,表示連接正在關閉。CLOSED:值為3,表示連接已經關閉,或者打開連接失敗。3、webSocket.bufferedAmountbufferedAmount屬性,表示還有多少字節的二進制數據沒有發送出去,可以用來判斷發送是否結束var data = new ArrayBuffer(10000000);webSocket.send(data);if (webSocket.bufferedAmount === 0) { // 發送完畢}?else?{???? //?發送還沒結束}4、webSocket.onopenonopen屬性,用于指定連接成功后的回調函數webSocket.onopen = function () { webSocket.send('Hello Server!');}webSocket.addEventListener('open',?function?(event)?{?? webSocket.send('Hello?Server!');});5、webSocket.oncloseonclose屬性,用于指定連接關閉后的回調函數webSocket.onclose = function(event) { var code = event.code; var reason = event.reason; var wasClean = event.wasClean; // handle close event};webSocket.addEventListener("close",?function(event)?{???? var?code?=?event.code;???? var?reason?=?event.reason;???? var?wasClean?=?event.wasClean;???? //?handle?close?event});6、webSocket.onmessageonmessage屬性,用于指定收到服務器數據后的回調函數webSocket.onmessage = function(event) { var data = event.data; // 處理數據};webSocket.addEventListener("message",?function(event)?{???? var?data?=?event.data;???? //?處理數據});注意:服務器數據可能是文本,也可能是二進制數據(blob對象或Arraybuffer對象)webSocket.onmessage = function(event){ if(typeof event.data === String) { console.log("Received data string"); ??}??????if(event.data?instanceof?ArrayBuffer){?????????? var?buffer?=?event.data;?????????? console.log("Received?arraybuffer");????????}}除了動態判斷收到的數據類型,也可以使用binaryType屬性,顯式指定收到的二進制數據類型// 收到的是 blob 數據webSocket.binaryType = "blob";webSocket.onmessage = function(e) { console.log(e.data.size);};// 收到的是 ArrayBuffer 數據webSocket.binaryType = "arraybuffer";webSocket.onmessage = function(e) { console.log(e.data.byteLength);};7、webSocket.onerroronerror屬性,用于指定報錯時的回調函數webSocket.onerror = function(event) { // handle error event};webSocket.addEventListener("error",?function(event)?{???? //?handle?error?event});8、webSocket.send()實例對象的send()方法用于向服務器發送數據發送文本的例子webSocket.send('your message');發送?Blob?對象的例子var file = document.querySelector('input[type="file"]').files[0];webSocket.send(file);發送?ArrayBuffer?對象的例子// Sending canvas ImageData as ArrayBuffervar img = canvas_context.getImageData(0, 0, 400, 320);var binary = new Uint8Array(img.data.length);for (var i = 0; i < img.data.length; i++) { binary[i] = img.data[i];}webSocket.send(binary.buffer);9、webSocket.close()實例對象的close()方法用于向服務器關閉連接webSocket.close()服務端如何實現
WebSocket 在服務端的實現非常豐富。Node.js、Java、C++、Python 等多種語言都有自己的解決方案常用的 Node 實現有以下三種:μWebSocketsSocket.IOWebSocket-NodeWebSocket小結
HTTP 和 WebSocket 有什么關系?Websocket 其實是一個新的應用層協議,跟 HTTP 協議基本沒有關系,只是為了兼容現有瀏覽器的握手規范而已,也可以說它是 HTTP 協議上的一種補充首先Websocket是基于HTTP協議的,或者說借用了HTTP的協議來完成一部分握手websocket握手階段:GET /chat HTTP/1.1Host: localhost:8080Origin: http://127.0.0.1:3000Connection: UpgradeUpgrade: websocketSec-WebSocket-Version: 13Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw==Sec-WebSocket-Protocol: chat, superchatConnection:?Upgrade表示要升級協議Upgrade:?websocket?表示要升級到websocket協議Sec-WebSocket-Version:?13表示websocket的版本,如果服務端不支持該版本,需要返回一個Sec-WebSocket-Version?header,里面包含服務端支持的版本號Sec-WebSocket-Key:是一個Base64?encode的值,這個是瀏覽器隨機生成的,與后面服務端響應首部的Sec-WebSocket-Accept是配套的,提供基本的防護,比如惡意的連接,或者無意的連接(Sec-WebSocket-Key,它由客戶端生成并發給服務端,用于證明服務端接收到的是一個可受信的連接握手,可以幫助服務端排除自身接收到的由非?WebSocket?客戶端發起的連接,該值是一串隨機經過?base64?編碼的字符串)Sec-WebSocket-Protocol:是一個用戶定義的字符串,用來區分同URL下,不同的服務所需要的協議然后服務器會返回下列東西,表示已經接受到請求,成功建立Websocket啦!HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat這里開始就是HTTP最后負責的區域了,告訴客戶,我已經成功切換協議啦~Sec-WebSocket-Accept:這個則是經過服務器確認,根據客戶端請求首部的Sec-WebSocket-Key計算出來的(Sec-WebSocket-Accept,服務端通過從客戶端請求頭中讀取?Sec-WebSocket-Key?與一串全局唯一的標識字符串(俗稱魔串)“258EAFA5-E914-47DA-?95CA-C5AB0DC85B11”做拼接,生成長度為160位的?SHA-1?字符串,然后進行?base64?編碼,作為?Sec-WebSocket-Accept?的值回傳給客戶端)計算公式:1、將Sec-WebSocket-Key跟258EAFA5-E914-47DA-95CA-C5AB0DC85B11拼接。2、通過SHA1計算出摘要,并轉成base64字符串toBase64(sha1(Sec-WebSocket-Key?+?258EAFA5-E914-47DA-95CA-C5AB0DC85B11?)?)Sec-WebSocket-Protocol:則是表示最終使用的協議至此,http已經完成它所有工作了,接下來就是完全按照Websocket協議進行通信了Sec-WebSocket-Key/Sec-WebSocket-Accept的主要作用在于提供基礎的防護,減少惡意連接、意外連接:1、避免服務端收到非法的websocket連接(比如http客戶端不小心請求連接websocket服務,此時服務端可以直接拒絕連接)2、確保服務端理解websocket連接。因為ws握手階段采用的是http協議,因此可能ws連接是被一個http服務器處理并返回的,此時客戶端可以通過Sec-WebSocket-Key來確保服務端認識ws協議。(并非百分百保險,比如總是存在那么些無聊的http服務器,光處理Sec-WebSocket-Key,但并沒有實現ws協議。。。)3、用瀏覽器里發起ajax請求,設置header時,Sec-WebSocket-Key以及其他相關的header是被禁止的。這樣可以避免客戶端發送ajax請求時,意外請求協議升級(websocket upgrade)4、可以防止反向代理(不理解ws協議)返回錯誤的數據。比如反向代理前后收到兩次ws連接的升級請求,反向代理把第一次請求的返回給cache住,然后第二次請求到來時直接把cache住的請求給返回(無意義的返回)5、Sec-WebSocket-Key主要目的并不是確保數據的安全性,因為Sec-WebSocket-Key、Sec-WebSocket-Accept的轉換計算公式是公開的,而且非常簡單,最主要的作用是預防一些常見的意外情況(非故意的)強調:Sec-WebSocket-Key/Sec-WebSocket-Accept 的換算,只能帶來基本的保障,但連接是否安全、數據是否安全、客戶端/服務端是否合法的 ws客戶端、ws服務端,其實并沒有實際性的保證websocket優點:1、支持雙向通信,實時性更強。2、不用頻繁送HTTP請求,只需要發送一個HTTP請求進行websocket握手,接下來則可以利用該TCP連接通過websocket協議通訊,避免了傳輸多個HTTP Header的浪費3、支持傳輸文本和二進制4、websocket數據傳輸是基于數據幀的,可以分片傳輸,不需要怕數據太大包容納不下5、支持擴展。ws協議定義了擴展,用戶可以擴展協議,或者實現自定義的子協議。(比如支持自定義壓縮算法等)WebSocket客戶端、服務端通信的最小單位是幀(frame),由1個或多個幀組成一條完整的消息(message)websocket出現之前的一些持久連接操作:1、長輪詢:建立連接 -> 傳輸數據 -> 保持連接 -> 。。。-> 響應 -> 關閉連接采取的是阻塞模型(一直打電話,沒收到就不掛電話),也就是說,客戶端發起連接后,如果服務端沒消息,就一直不返回Response給客戶端。直到有消息才返回,返回完之后,客戶端再次建立連接,周而復始。需要有很高的并發,也就是說同時接待客戶的能力。(場地大小)服務器hold連接會消耗資源,返回數據順序無保證,難于管理維護2、ajax輪詢:建立連接 -> 傳輸數據 -> 響應 -> 關閉連接 -> 定時循環上面的過程定時向后臺發請求,需要服務器有很快的處理速度和資源。(速度)請求中有大半是無用,浪費帶寬和服務器資源3、長連接:建立連接 -> 傳輸數據 -> 保持連接 -> 傳輸數據 -> 。。。-> 關閉連接http1.0默認進行短連接,通過使用Connection: keep-alive進行長連接,http1.1默認進行持久連接。在一次 TCP 連接中可以完成多個 http 請求,但是對每個請求仍然要單獨發 header,keep-alive不會永久保持連接,它有一個保持時間,可以在不同的服務器軟件(如Nginx\Apache)中設定這個時間啟用keep-alive模式會更高效,性能更高。因為避免了建立/釋放連接的開銷以上持久連接的缺點:1、被動性 - 只能由客戶端發送請求2、在傳統的方式上,要不斷的建立和關閉連接,由于http是非狀態性的,每次都要重新傳輸identity info(鑒別信息),來告訴服務端你是誰,解析耗時,耗資源,效率還低3、http1.1串行單線程處理,響應是有順序的,只有上一個請求完成后,下一個才能響應。一旦有任務處理超時等,后續任務只能被阻塞(線頭阻塞)4、keep-alive雙方并沒有建立正真的連接會話,服務端可以在任何一次請求完成后關閉websocket長時間沒有通信會自動斷開的原因?利用nginx代理websocket的時候,發現客戶端和服務器握手成功后,如果在60s時間內沒有數據交互,連接就會自動斷開nginx.conf 文件里location 中的proxy_read_timeout 默認60s斷開保持持久連接的做法:1、把服務器的默認時間改大 + 發送心跳機制2、定時檢測客戶端是否已經斷開連接,斷開重連構建打包工具Rollup.js入門指南使用React的注意點(一)你不可不知道的React生命周期強推一款臨時郵件神器總結
以上是生活随笔為你收集整理的c++ websocket客户端_你要的websocket都在这,收好不谢~~~的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python生成100个随机数_Pyth
- 下一篇: angular五大服务顺序_建议收藏 |