初探WebSocket

来源:https://www.cnblogs.com/xiaoloulan/archive/2018/03/15/8573344.html
-Advertisement-
Play Games

初探WebSocket node websocket socket.io 我們平常開發的大部分web頁面都是主動‘拉’的形式,如果需要更新頁面內容,則需要“刷新”一個,但Slack工具卻能主動收到信息,好像服務端能主動給客戶端推送信息,請研究一下這是怎麼實現的。 WebSocket websocke ...


初探WebSocket

node websocket socket.io


我們平常開發的大部分web頁面都是主動‘拉’的形式,如果需要更新頁面內容,則需要“刷新”一個,但Slack工具卻能主動收到信息,好像服務端能主動給客戶端推送信息,請研究一下這是怎麼實現的。

WebSocket

OSI七層模型

websocket是HTML5中新引進的一種 協議 ,它是一種協議就像(HTTP,FTP在tcp/ip協議棧中屬於應用層)而不是簡單的一個函數。它本身及基於TCP協議的一種新的協議。

WebSocket的產生

websocket是基於web的實時性而產生的,說到這裡就不得不要追溯一下web的歷史了,在2005年(也就是ajax還沒誕生)以前,我們如果想要在一個頁面顯示顯示不同的內容,或者說頁面內跳轉,只能是通過點擊然後路由跳轉,在ajax誕生之後,網頁開始變得動態了。但是所有的HTTP通信還都是由客戶端控制的,這就要需要長連接,定期輪詢或者長輪詢,來和伺服器溝通來更新數據。

WebSocket之前的伺服器“推”的技術

  1. 定期輪詢(ajax輪詢):瀏覽器在特定的時間給伺服器發送請求,查看伺服器是否有信息數據。定期輪詢

優點:後端程式編寫比較容易。
缺點:請求中有大半是無用,浪費帶寬和伺服器資源。
實例:適於小型應用。

  1. 長輪詢:其實和上面的原理差不多,是對ajax輪詢進行了改進和提高。客戶端和服務端建立連接之後,一直保持通信(阻塞模式),如果伺服器沒有新消息就一直保持通信,直到伺服器有新的消息,然後返回給客戶端,客戶端與伺服器斷開連接,此時客戶端可以繼續和伺服器進行連接。長鏈接

優點:在無消息的情況下不會頻繁的請求,耗費資源小。
缺點:伺服器hold連接會消耗資源,返回數據順序無保證,難於管理維護。
實例:舊的 WebQQ、Hi網頁版、Facebook IM。

  1. 流控制:通常就是在客戶端的頁面使用一個隱藏的視窗向服務端發出一個長連接的請求。伺服器端接到這個請求後作出回應並不斷更新連接狀態以保證客戶端和服務 器端的連接不過期。通過這種機制可以將伺服器端的信息源源不斷地推向客戶端。比如在頁面里嵌入一個隱蔵iframe,將這個隱蔵iframe的src屬性設為對一個長連接的請求或是採用xhr請求,伺服器端就能源源不斷地往客戶端輸入數據。

SSE,Comet,使用長鏈接進行通訊。流操作

優點:消息即時到達,不發無用請求;管理起來也相對方便。
缺點:伺服器維護一個長連接會增加開銷。
實例:Gmail聊天

  1. Flash Socket:在頁面中內嵌入一個使用了Socket類的 Flash 程式JavaScript通過調用此Flash程式提供的Socket介面與伺服器端的Socket介面進行通信,JavaScript在收到伺服器端傳送的信息後控制頁面的顯示。

優點:實現真正的即時通信,而不是偽即時。
缺點:客戶端必須安裝Flash插件;非HTTP協議,無法自動穿越防火牆。
實例:網路互動游戲。

HTTP1.1和長鏈接

以上幾種伺服器“推”的技術中:長輪詢和流控制其實都是基於長鏈接來實現的,也就是 http1.1 中所謂的 keep-alive。在一個TCP連接上可以傳送多個HTTP請求和響應,減少了建立和關閉連接的消耗和延遲。

HTTP是無狀態的,也就是說,瀏覽器和伺服器每進行一次HTTP操作,就建立一次連接,但任務結束就中斷連接。如果客戶端瀏覽器訪問的某個HTML或其他類型的Web頁中包含有其他的Web資源,如JavaScript文件、圖像文件、CSS文件等;當瀏覽器每遇到這樣一個Web資源,就會建立一個HTTP會話

HTTP1.1和HTTP1.0相比較而言,最大的區別就是HTTP1.1預設支持持久連接(最新的 http1.0 可以顯示的指定 keep-alive),但還是無狀態的,或者說是不可以信任的。

在向客戶發送所請求文件的同時,伺服器並沒有存儲關於該客戶的任何狀態信息。即便某個客戶在幾秒鐘內再次請求同一個對象,伺服器也不會響應說:自己剛剛給它發送了這個對象。相反,伺服器重新發送這個對象,因為它已經徹底忘記早先做過什麼。既然HTTP伺服器不維護客戶的狀態信息,我們於是 說HTTP是一個無狀態的協議(stateless protocol)。

基於http協議的長連接減少了請求,減少了建立連接的時間,但是每次交互都是由客戶端發起的,客戶端發送消息,服務端才能返回客戶端消息。因為客戶端也不知道服務端什麼時候會把結果準備好,所以客戶端的很多請求是多餘的,僅是維持一個心跳,浪費了帶寬。

WebSocket

WebSocket簡介

WebSocket 協議在2008年誕生,2011年成為國際標準。所有瀏覽器都已經支持了。WebSocket通信協議於2011年被IETF定為標準RFC 6455,並被RFC7936所補充規範。

關於HTML5的故事很多人都是知道的,w3c放棄了HTML,然後有一群人(也有說是這些人供職的公司,不過官方的文檔上是說的個人)創立了WHATWG組織來推動HTML語言的繼續發展,同時,他們還發展了很多關於Web的技術標準,這些標準不斷地被官方所接受。WebSocket就屬於WHATWG發佈的Web Application的一部分(即HTML5)的產物。

它的最大特點就是,伺服器可以主動向客戶端推送信息,客戶端也可以主動向伺服器發送信息,是真正的雙向平等對話,屬於伺服器推送技術的一種。

  • 建立在 TCP 協議之上,伺服器端的實現比較容易。

  • 與 HTTP 協議有著良好的相容性。預設埠也是80和443,並且握手階段採用 HTTP 協議,因此握手時不容易屏蔽,能通過各種 HTTP 代理伺服器。

  • 數據格式比較輕量,性能開銷小,通信高效。

  • 可以發送文本,也可以發送二進位數據。

  • 沒有同源限制,客戶端可以與任意伺服器通信。

  • 協議標識符是ws(如果加密,則為wss),伺服器網址就是 URL。

websocket

其中 Upgrade: websocket Connection: Upgrade 告訴伺服器我們發起的是一個 WebSocket 請求。Sec-WebSocket-Key 是一個 Base64encode 的值,這個是瀏覽器隨機生成的,驗證伺服器是不是真的是Websocket助理。
然後,Sec_WebSocket-Protocol 是一個用戶定義的字元串,用來區分同URL下,不同的服務所需要的協議。
最後,Sec-WebSocket-Version 是告訴伺服器所使用的WebsocketDraft(協議版本)。

HTML5 Web Socket API

詳細介面文檔:MDN WebSocket

創建對象:
var ws = new WebSocket(url,name);
url為WebSocket伺服器的地址,name為發起握手的協議名稱,為可選擇項。

發送文本消息:
ws.send(msg);
msg為文本消息,對於其他類型的可以通過二進位形式發送。

接收消息:
ws.onmessage = (function(){...})();

錯誤處理:
ws.onerror = (function(){...})();

關閉連接:
ws.close();

我們藉助這個測試介面 wss://echo.websocket.org 來做一個小demo。

公用html(下麵的代碼基本也是這個結構):

<h1>客戶端簡單例子</h1>
<i>這裡我們走Kaazing WebSocket為我們提供的介面,這個介面將完整返回我們所發送的數據。</i>
<p>狀態:<strong id="state"></strong></p>
<p>返回數據:<strong id="msg"></strong></p>
<input id="sendText" type="text" name="">
<button id="sendBtn">發送</button>
<button id="closeBtn">關閉</button>

JS:

var show = document.getElementById('state'),
    msg  = document.getElementById('msg'),
    st   = document.getElementById('sendText'),
    sb   = document.getElementById('sendBtn');

if ("WebSocket" in window) {
  var ws = new WebSocket('wss://echo.websocket.org');

  ws.onopen = function(e) { 
    show.innerText = 'WebSocket連接成功~';
    ws.send('Hello WebSockets!');
  };

  ws.onmessage = function(e) {
    msg.innerText = e.data;
  };

  ws.onclose = function(e) {
    show.innerText = 'WebSocket連接關閉~';
  }

  sb.addEventListener('click',function(){
    ws.send(st.value);
  })

}else{
  alert('你的瀏覽器不支持WebSocket');
}

demo1

nodejs-websocket

nodejs-websocket是一個nodeJs的模塊,我們可以用它來輕易地為我們之前的代碼單獨搭建一個WebSocket的nodeJs服務端。

yarn add nodejs-websocket
var ws = require("nodejs-websocket")

// Scream server example: "hi" -> "HI!!!"
var server = ws.createServer(function (conn) {
    console.log("New connection")
    conn.on("text", function (str) {
        console.log("Received "+str)
        conn.sendText(str.toUpperCase()+"!!!")
    })
    conn.on("close", function (code, reason) {
        console.log("Connection closed")
    })
}).listen(8001)

Socket.io

在某種程度上,socket.io就是websocket,其實socket.io與websocket不是一回事,而且websocket可以說是socket.io的一個子集,socket.io的底層實現其實有5種方式,websocket只是其中一種,只不過在預設的情況下,我們建立的socket.io連接,底層也是調用websocket的實例。當我們io.connect()建立一個socket連接的時候,返回的是namespace實例,namespace實例中有個socket實例,當新建一個連接,或者發送一條消息的時候,namespace->socket->transport->websocket(xhrpolling...),其實發送一條消息真正的發送者還是底層的websocket或是xhrpolling或其他的幾種,而socket.io只是一個組織者,當我們需要建立連接的時候,它自己會在其內部挑選一種連接方式,然後實現連接。

Socket.io都實現了Polling中的那些通信機制呢?

  • Adobe® Flash® Socket
  • AJAX long polling
  • AJAX multipart streaming
  • Forever Iframe
  • JSONP Polling

WebSocket和HTTP和Socket

應用層的協議,WebSocket在現代的軟體開發中被越來越多的實踐,和HTTP有一些相似的地方,而且有人也會把WebSocket和Socket混為一談,那麼他們之間到底有什麼異同呢?

WebSocket和HTTP

我們先看兩個協議的截圖來領會下。

websocket

http

相同點
  1. 都是基於TCP的應用層協議。
  2. 都使用Request/Response模型進行連接的建立。
  3. 在連接的建立過程中對錯誤的處理方式相同,在這個階段WS可能返回和HTTP相同的返回碼。
  4. 都可以在網路中傳輸數據。
不同點
  1. WS使用HTTP來建立連接,但是定義了一系列新的header域,這些域在HTTP中並不會使用。
  2. WS的連接不能通過中間人來轉發,它必須是一個直接連接。
  3. WS連接建立之後,通信雙方都可以在任何時刻向另一方發送數據。
  4. WS連接建立之後,數據的傳輸使用幀來傳遞,不再需要Request消息。
  5. WS的數據幀有序。

WebSocket和Socket

其實就像Java和JavaScript一樣,WebSocket和Socket並沒有太大的關係。

Socket可以有很多意思,和IT較相關的本意大致是指在端到端的一個連接中,這兩個端叫做Socket。對於IT從業者來說,它往往指的是TCP/IP網路環境中的兩個連接端,大多數的API提供者(如操作系統,JDK)往往會提供基於這種概念的介面,所以對於開發者來說也往往是在說一種編程概念。同時,操作系統中進程間通信也有Socket的概念,但這個Socket就不是基於網路傳輸層的協議了。

Socket 其實並不是一個協議。它工作在 OSI 模型會話層(第5層),是為了方便大家直接使用更底層協議(一般是 TCP 或 UDP )而存在的一個抽象層。

Socket是應用層與TCP/IP協議族通信的中間軟體抽象層,它是一組介面。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket介面後面,對用戶來說,一組簡單的介面就是全部,讓Socket去組織數據,以符合指定的協議。

http

主機 A 的應用程式要能和主機 B 的應用程式通信,必須通過 Socket 建立連接,而建立 Socket 連接必須需要底層 TCP/IP 協議來建立 TCP 連接。建立 TCP 連接需要底層 IP 協議來定址網路中的主機。我們知道網路層使用的 IP 協議可以幫助我們根據 IP 地址來找到目標主機,但是一臺主機上可能運行著多個應用程式,如何才能與指定的應用程式通信就要通過 TCP 或 UPD 的地址也就是埠號來指定。這樣就可以通過一個 Socket 實例唯一代表一個主機上的一個應用程式的通信鏈路了。

而 WebSocket 則不同,它是一個完整的 應用層協議,包含一套標準的 API 。

所以,從使用上來說,WebSocket 更易用,而 Socket 更靈活。

瀏覽器支持

瀏覽器支持

websocket api在瀏覽器端的廣泛實現似乎只是一個時間問題了, 值得註意的是伺服器端沒有標準的api, 各個實現都有自己的一套api, 並且tcp也沒有類似的提案, 所以使用websocket開發伺服器端有一定的風險.可能會被鎖定在某個平臺上或者將來被迫升級。

本文相關的Demo已經放在作者的Github上:小樓蘭的github


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 說到模塊化,不可否認這已經成為了前端開發的一個共識,而本人在開發中也逐漸接受了模塊化這種理念,並且深深滴體會到模塊化開發的好處。為啥這麼說呢?來看一段簡單的代碼:(不使用模塊化) 這是在未使用模塊化之前經常可以見到的一種現象:把一堆js放在body底部,可是你知道嗎?這種方式存在兩個很大的問題: 1 ...
  • 單行省略 多行省略 省略都需要width屬性限制才能生效 ...
  • 我們都知道JavaScript是一門弱類型(或稱動態類型)的語言,即變數的類型是不確定的。 上面的代碼中,變數num起初是一個數值,後來又變成一個字元串。變數類型完全由當前值決定。這種類型就叫弱類型。 我們知道,在編程語言中,數據本身和運算之間都是有類型的。 在強類型的編程語言中,不同類型的變數是不 ...
  • 按位非 按位非操作符由一個波浪線(~)表示,執行按位非的結果就是返回數值的反碼 現在讓我來看幾個例子 例子1 例子2 例子3 結論 通過上面的例子我們可以知道對於整數,按位非就是操作數的負值減1. 但是對於浮點數就比較麻煩了,操作浮點數時,會直接捨去小數部分,在取負值減1 利用這點我們可以可以使用~ ...
  • 在Angular中使用依賴註入(DI)的時候,我們一般會使用 。其實要做同樣的事我們還有另外一個選擇: 。 允許我們定義只對組件的view可見的provider。下麵我們用例子詳細的說明這一點。 假設我們有一個簡單的服務: 這個服務很簡單,只需要列印出在哪裡調用了該服務。 然後有一個子組件,是用來投 ...
  • 什麼是作用域? 作用域規定變數在什麼地方可用。 函數級作用域 1.函數外聲明的變數為全局變數,函數內可以直接訪問全局變數: 2.JavaScript變數的作用域是 函數級 的,只有函數可以產生新的作用域,而非塊級: 變數x雖然在塊語句(if)中聲明並賦值,但它的作用域是函數a,所以在函數a的任何位置 ...
  • break 語句和 continue 語句 break語句和continue語句都具有跳轉作用,可以讓代碼不按既有的順序執行。 break語句用於跳出代碼塊或迴圈。 top: for (var i = 0; i 帶符號位的右移運算符(zero filled right shift):符號為 void ...
  • 代碼如下: 1 /* 2 * Ext表格自定義分頁大小 插件 3 * 4 * 示例PagingToolbar 5 brr = new Ext.ux.PagingToolbar({ 6 plugins: new Ext.ui.plugins.ComboPageSize(), 7 pageSize : ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...