成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

WebSocket其實(shí)沒那么難

CoderDock / 588人閱讀

摘要:服務(wù)端確認(rèn)協(xié)議版本,升級為協(xié)議。自己寫了一個(gè)例子,服務(wù)端在開始連接后,利用定時(shí)器主動(dòng)向客戶端發(fā)送隨機(jī)數(shù),客戶端也可以發(fā)給服務(wù)器消息,然后服務(wù)器返回這條消息給客戶端。

寫在前面

webSocket是一項(xiàng)可以讓服務(wù)器將數(shù)據(jù)主動(dòng)推送給客戶端的技術(shù)。前幾天寫了一個(gè)日志功能,日志數(shù)據(jù)需要實(shí)時(shí)更新。正好項(xiàng)目中有封裝好的WebSocket組件,且接口支持webSocket,就用它實(shí)現(xiàn)了。也是第一次用,簡單研究了一下,分享出來。
文章示例代碼:https://github.com/neroneroff...

什么是WebSocket

首先需要明白webSocket的概念,下邊是維基百科的解釋

WebSocket是一種通信協(xié)議,可在單個(gè)TCP連接上進(jìn)行全雙工通信。WebSocket使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,
允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù)。在WebSocket API中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就可以建立持久性的連接,
并進(jìn)行雙向數(shù)據(jù)傳輸。

首先,要明白WebSocket是一種通信協(xié)議,區(qū)別于HTTP協(xié)議,HTTP協(xié)議只能實(shí)現(xiàn)客戶端請求,服務(wù)端響應(yīng)的這種單項(xiàng)通信。
而WebSocket可以實(shí)現(xiàn)客戶端與服務(wù)端的雙向通訊,說白了,最大也是最明顯的區(qū)別就是可以做到服務(wù)端主動(dòng)將消息推送給客戶端。

其余的特點(diǎn)有:

握手階段采用 HTTP 協(xié)議。

數(shù)據(jù)格式輕量,性能開銷小??蛻舳伺c服務(wù)端進(jìn)行數(shù)據(jù)交換時(shí),服務(wù)端到客戶端的數(shù)據(jù)包頭只有2到10字節(jié),客戶端到服務(wù)端需要加上另外4字節(jié)的掩碼。
HTTP每次都需要攜帶完整頭部。

更好的二進(jìn)制支持,可以發(fā)送文本,和二進(jìn)制數(shù)據(jù)

沒有同源限制,客戶端可以與任意服務(wù)器通信

協(xié)議標(biāo)識(shí)符是ws(如果加密,則是wss),請求的地址就是后端支持websocket的API。

幾種與服務(wù)端實(shí)時(shí)通信的方法

我們都知道,不使用WebSocket與服務(wù)器實(shí)時(shí)交互,一般有兩種方法。AJAX輪詢和Long Polling長輪詢。

AJAX輪詢

AJAX輪詢是定時(shí)發(fā)送請求,也就是普通的客戶端與服務(wù)端通信過程,只不過是無限循環(huán)發(fā)送,這樣,可以保證服務(wù)端一旦有最新消息,就可以被客戶端獲取。

Long Polling長輪詢

Long Polling長輪詢是客戶端和瀏覽器保持一個(gè)長連接,等服務(wù)端有消息返回,斷開。
然后再重新連接,也是個(gè)循環(huán)的過程,無窮盡也。。。

客戶端發(fā)起一個(gè)Long Polling,服務(wù)端如果沒有數(shù)據(jù)要返回的話,
會(huì)hold住請求,等到有數(shù)據(jù),就會(huì)返回給客戶端??蛻舳擞謺?huì)再次發(fā)起一次Long Polling,再重復(fù)一次上面的過程。

缺點(diǎn)

上邊這兩種方式都有個(gè)致命的弱點(diǎn),開銷太大,被動(dòng)性。假設(shè)并發(fā)很高的話,這對服務(wù)端是個(gè)考驗(yàn)。
而WebSocket一次握手,持久連接,以及主動(dòng)推送的特點(diǎn)可以解決上邊的問題,又不至于損耗性能。

WebSocket連接過程

客戶端發(fā)起HTTP握手,告訴服務(wù)端進(jìn)行WebSocket協(xié)議通訊,并告知WebSocket協(xié)議版本。服務(wù)端確認(rèn)協(xié)議版本,升級為WebSocket協(xié)議。之后如果有數(shù)據(jù)需要推送,會(huì)主動(dòng)推送給客戶端。

連接開始時(shí),客戶端使用HTTP協(xié)議和服務(wù)端升級協(xié)議,升級完成后,后續(xù)數(shù)據(jù)交換遵循WebSocket協(xié)議。我們看看Request Headers

Accept-Encoding: gzip, deflate, br
Accept-Language: zh,zh-TW;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6
Cache-Control: no-cache
Connection: Upgrade
Host: 127.0.0.1:3000
Origin: http://localhost:3000
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: bwb9SFiJONXhQ/A4pLaXIg==
Sec-WebSocket-Version: 13
Upgrade: websocket

重點(diǎn)字段是這些:

Connection: Upgrade 表示要升級協(xié)議

Upgrade: websocket 要升級協(xié)議到websocket協(xié)議

Sec-WebSocket-Version 表示websocket的版本。如果服務(wù)端不支持該版本,需要返回一個(gè)Sec-WebSocket-Versionheader,里面包含服務(wù)端支持的版本號(hào)。

Sec-WebSocket-Key 對應(yīng)服務(wù)端響應(yīng)頭的Sec-WebSocket-Accept,由于沒有同源限制,websocket客戶端可任意連接支持websocket的服務(wù)。這個(gè)就相當(dāng)于一個(gè)鑰匙一把鎖,避免多余的,無意義的連接。

再看看看服務(wù)端響應(yīng)的 Response Headers

Connection: Upgrade
Sec-WebSocket-Accept: 2jrbCWSCPlzPtxarlGTp4Y8XD20=
Upgrade: websocket

關(guān)鍵是這個(gè)字段

Sec-WebSocket-Accept: 用來告知服務(wù)器愿意發(fā)起一個(gè)websocket連接, 值根據(jù)客戶端請求頭的Sec-WebSocket-Key計(jì)算出來

WebSocket API

客戶端若想要與支持webScoket的服務(wù)器通信,可以使用WebSocket構(gòu)造函數(shù)返回WebSocket對象。

const ws = new WebSocket("ws://localhost:3000/websocket");

這樣,客戶端就會(huì)與服務(wù)端開始連接。

返回的實(shí)例對象的屬性:

WebSocket.onopen: 連接成功后的回調(diào)

WebSocket.onclose: 連接關(guān)閉后的回調(diào)

WebSocket.onerror: 連接失敗后的回調(diào)

WebSocket.onmessage: 客戶端接收到服務(wù)端數(shù)據(jù)的回調(diào)

webSocket.bufferedAmount: 未發(fā)送至服務(wù)器的二進(jìn)制字節(jié)數(shù)

WebSocket.binaryType: 使用二進(jìn)制的數(shù)據(jù)類型連接

WebSocket.protocol : 服務(wù)器選擇的下屬協(xié)議

WebSocket.url : WebSocket 的絕對路徑

WebSocket.readyState: 當(dāng)前連接狀態(tài),對應(yīng)的四個(gè)常量

名稱
WebSocket.CONNECTING 0
WebSocket.OPEN 1
WebSocket.CLOSING 2
WebSocket.CLOSED 3

方法:

WebSocket.close() 關(guān)閉當(dāng)前連接

WebSocket.send(data) 向服務(wù)器發(fā)送數(shù)據(jù)

示例

講了那么多概念以后,終于可以看看怎么用了。實(shí)現(xiàn)WebSocket通信,需要客戶端和服務(wù)端配合。

自己寫了一個(gè)例子,服務(wù)端在開始連接后,利用定時(shí)器主動(dòng)向客戶端發(fā)送隨機(jī)數(shù),客戶端也可以發(fā)給服務(wù)器消息,
然后服務(wù)器返回這條消息給客戶端。客戶端就是js+html,服務(wù)端用了express + express-ws來實(shí)現(xiàn)。
代碼在這里:https://github.com/neroneroff... 可以clone下來,安裝依賴,npm start運(yùn)行看下效果。

客戶端

前端頁面,最終效果如以上效果圖:


  

服務(wù)端返回的消息

js,使用webSocket的代碼都在這里。做的事情就是給頁面的元素綁定事件。
然后創(chuàng)建WebSocket對象,監(jiān)聽對象的連接、接收消息、關(guān)閉等事件,將數(shù)據(jù)反饋到頁面中

const msgBox = document.getElementById("msg-need-send")
const sendBtn = document.getElementById("send-btn")
const exit = document.getElementById("exit")
const receiveBox = document.getElementById("receive-box")

// 創(chuàng)建一個(gè)webSocket對象
const ws = new WebSocket("ws://127.0.0.1:3000/websocket/test")
ws.onopen = e => {
  // 連接后監(jiān)聽
  console.log(`WebSocket 連接狀態(tài): ${ws.readyState}`)
}

ws.onmessage = data => {
  // 當(dāng)服務(wù)端返回?cái)?shù)據(jù)的時(shí)候,放到頁面里
  receiveBox.innerHTML += `

${data.data}

` receiveBox.scrollTo({ top: receiveBox.scrollHeight, behavior: "smooth" }) } ws.onclose = data => { // 監(jiān)聽連接關(guān)閉 console.log("WebSocket連接已關(guān)閉") console.log(data); } sendBtn.onclick = () => { // 點(diǎn)擊發(fā)送按鈕。將數(shù)據(jù)發(fā)送給服務(wù)端 ws.send(msgBox.value) } exit.onclick = () => { // 客戶端主動(dòng)關(guān)閉連接 ws.close() }
服務(wù)端

考慮到了模塊化開發(fā),沒有直接把代碼放到直接創(chuàng)建服務(wù)的文件中。而是使用了路由,給webSocket服務(wù)分配一個(gè)多帶帶的接口

const express = require("express");
const expressWs = require("express-ws")
const router = express.Router()
expressWs(router);

router.ws("/test", (ws, req) => {
  ws.send("連接成功")
  let interval
  // 連接成功后使用定時(shí)器定時(shí)向客戶端發(fā)送數(shù)據(jù),同時(shí)要注意定時(shí)器執(zhí)行的時(shí)機(jī),要在連接開啟狀態(tài)下才可以發(fā)送數(shù)據(jù)
  interval = setInterval(() => {
    if (ws.readyState === ws.OPEN) {
      ws.send(Math.random().toFixed(2))
    } else {
      clearInterval(interval)
    }
  }, 1000)
  // 監(jiān)聽客戶端發(fā)來的數(shù)據(jù),直接將信息原封不動(dòng)返回回去
  ws.on("message", msg => {
    ws.send(msg)
  })
})


module.exports = router

最后看一下數(shù)據(jù)交互的過程

總結(jié)

上邊簡單實(shí)現(xiàn)了一個(gè)webSocket通信。實(shí)際的東西還有很多,比如webSocket擴(kuò)展,心跳檢測,數(shù)據(jù)加密,身份認(rèn)證等知識(shí)點(diǎn)。但自己也需要再去研究,所以先不做介紹了。

相關(guān)文章

WebSocket協(xié)議:5分鐘從入門到精通

WebSocket 教程--阮一峰

WebSocket API

express-ws文檔

歡迎關(guān)注我的公眾號(hào): 一口一個(gè)前端,不定期分享我所理解的前端知識(shí)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/105858.html

相關(guān)文章

  • socket.io原理和實(shí)戰(zhàn)

    摘要:就是為了解決這一問題產(chǎn)生的,現(xiàn)在已經(jīng)寫入標(biāo)準(zhǔn),主流瀏覽器基本支持。 由于最近寫項(xiàng)目要使用socekt.io技術(shù),于是研究了一段時(shí)間,把自己早期學(xué)習(xí)階段寫的小游戲改造了一下,變成了一個(gè)比較完整的小程序。點(diǎn)擊這里可以體驗(yàn)游戲,建議使用手機(jī)模式查看,也可以下載打包好的webapp,安卓版已上架酷安市場,掃碼可下載體驗(yàn): showImg(https://segmentfault.com/img...

    ivyzhang 評論0 收藏0
  • 從零到一,擼一個(gè)在線斗地主(下篇)

    摘要:原文從零到一,擼一個(gè)在線斗地主下篇作者上篇回顧我們說了斗地主游戲的渲染展示部分,最后也講了下中交互的情況,下篇的重點(diǎn)就是游戲邏輯。 原文:從零到一,擼一個(gè)在線斗地主(下篇) | AlloyTeam作者:TAT.vorshen 上篇回顧:我們說了斗地主游戲的渲染展示部分,最后也講了下canvas中交互的情況,下篇的重點(diǎn)就是游戲邏輯。 邏輯主要分成兩塊:流程邏輯和撲克牌對比邏輯。 gith...

    CloudDeveloper 評論0 收藏0
  • Kubernetes Resource監(jiān)控怎么做

    摘要:運(yùn)行得十分好,總是使用并且返回消息。這個(gè)問題的提出意味著通過實(shí)施你自己的函數(shù)來使用原套,從回應(yīng)到讀取。額外的緩沖是因?yàn)檎埱笫褂玫氖窃继捉幼值纳晌募椒◤闹凶x取數(shù)據(jù)。手動(dòng)進(jìn)行所以如何從使用通過自己發(fā)出請求和處理響應(yīng)。 Kubernetes有一個(gè)之前系統(tǒng)用來做很多工作的REST-ish HTTP API。這個(gè)API是開放的,而且文檔十分齊全,很容易整合,可以從代碼方面管理集群。然而這個(gè)...

    ethernet 評論0 收藏0
  • 什么是 HTML 5?

    摘要:該區(qū)域代表可以被所控制的畫布。那么現(xiàn)在第二個(gè)問題,識(shí)別該文檔,這或許不是大部分用戶的需求,但小部分用戶并不意味著人數(shù)少。因此一個(gè)基于的請求于標(biāo)準(zhǔn)內(nèi)提出。 前言 作為程序員,技術(shù)的落實(shí)與鞏固是必要的,因此想到寫個(gè)系列,名為 why what or how 每篇文章試圖解釋清楚一個(gè)問題。 這次的 why what or how 主題:現(xiàn)在幾乎所有人都知道了 HTML5 ,那么 H5 到底相...

    zhaofeihao 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<