<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          零距離接觸websocket

          共 4936字,需瀏覽 10分鐘

           ·

          2020-11-08 04:45

          來源 | https://juejin.im/post/6876301731966713869

          什么是WebSocket

          定義

          Websocket是一個持久化的網(wǎng)絡通信協(xié)議,可以在單個 TCP 連接上進行全雙工通訊,沒有了Request和Response的概念,兩者地位完全平等,連接一旦建立,客戶端和服務端之間實時可以進行雙向數(shù)據(jù)傳輸。

          關聯(lián)和區(qū)別

          • HTTP
          1. HTTP是非持久的協(xié)議,客戶端想知道服務端的處理進度只能通過不停地使用 Ajax進行輪詢或者采用 long poll 的方式來,但是前者對服務器壓力大,后者則會因為一直等待Response造成阻塞
          2. 雖然http1.1默認開啟了keep-alive長連接保持了這個TCP通道使得在一個HTTP連接中,可以發(fā)送多個Request,接收多個Response,但是一個request只能有一個response。而且這個response也是被動的,不能主動發(fā)起。
          3. websocket雖然是獨立于HTTP的一種協(xié)議,但是websocket必須依賴 HTTP 協(xié)議進行一次握手(在握手階段是一樣的),握手成功后,數(shù)據(jù)就直接從 TCP通道傳輸,與 HTTP 無關了,可以用一張圖理解兩者有交集,但是并不是全部。
          • socket
          1. socket也被稱為套接字,與HTTP和WebSocket不一樣,socket不是協(xié)議,它是在程序層面上對傳輸層協(xié)議(可以主要理解為TCP/IP)的接口封裝。可以理解為一個能夠提供端對端的通信的調用接口(API)
          2. 對于程序員而言,其需要在 A 端創(chuàng)建一個 socket 實例,并為這個實例提供其所要連接的 B 端的 IP 地址和端口號,而在 B 端創(chuàng)建另一個 socket 實例,并且綁定本地端口號來進行監(jiān)聽。當 A 和 B 建立連接后,雙方就建立了一個端對端的 TCP 連接,從而可以進行雙向通信。WebSocekt借鑒了 socket 的思想,為 client 和 server 之間提供了類似的雙向通信機制

          應用場景

          WebSocket可以做彈幕、消息訂閱、多玩家游戲、協(xié)同編輯、股票基金實時報價、視頻會議、在線教育、聊天室等應用實時監(jiān)聽服務端變化

          Websocket握手

          • Websocket握手請求報文:
          GET /chat HTTP/1.1Host: server.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13Origin: http://example.com
          下面是與傳統(tǒng) HTTP 報文不同的地方:
          Upgrade: websocketConnection: Upgrade
          表示發(fā)起的是 WebSocket 協(xié)議
          Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13
          Sec-WebSocket-Key 是由瀏覽器隨機生成的,驗證是否可以進行Websocket通信,防止惡意或者無意的連接。
          Sec_WebSocket-Protocol 是用戶自定義的字符串,用來標識服務所需要的協(xié)議
          Sec-WebSocket-Version ?表示支持的 WebSocket 版本。
          • 服務器響應:
          HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat
          101 響應碼 表示要轉換協(xié)議。
          Connection: Upgrade 表示升級新協(xié)議請求。
          Upgrade: websocket 表示升級為 WebSocket 協(xié)議。
          Sec-WebSocket-Accept 是經(jīng)過服務器確認,并且加密過后的 Sec-WebSocket-Key。用來證明客戶端和服務器之間能進行通信了。
          Sec-WebSocket-Protocol 表示最終使用的協(xié)議。
          至此,客戶端和服務器握手成功建立了Websocket連接,HTTP已經(jīng)完成它所有工作了,接下來就是完全按照Websocket協(xié)議進行通信了。

          關于Websocket

          WebSocket心跳

          可能會有一些未知情況導致SOCKET斷開,而客戶端和服務端卻不知道,需要客戶端定時發(fā)送一個心跳 Ping 讓服務端知道自己在線,而服務端也要回復一個心跳 Pong告訴客戶端自己可用,否則視為斷開

          WebSocket狀態(tài)

          WebSocket 對象中的readyState屬性有四種狀態(tài):
          • 0: 表示正在連接
          • 1: 表示連接成功,可以通信了
          • 2: 表示連接正在關閉
          • 3: 表示連接已經(jīng)關閉,或者打開連接失敗

          WebSocket實踐

          服務端接收發(fā)送消息

          WebSocket的服務端部分,本文會以Node.js搭建
          安裝express和負責處理WebSocket協(xié)議的ws:
          npm install express ws
          安裝成功后的package.json:


          接著在根目錄創(chuàng)建server.js文件:
          //引入express 和 wsconst express = require('express');const SocketServer = require('ws').Server;
          //指定開啟的端口號const PORT = 3000;
          // 創(chuàng)建express,綁定監(jiān)聽3000端口,且設定開啟后在consol中提示const server = express().listen(PORT, () => console.log(`Listening on ${PORT}`));
          // 將express交給SocketServer開啟WebSocket的服務const wss = new SocketServer({ server });
          //當 WebSocket 從外部連接時執(zhí)行wss.on('connection', (ws) => { //連接時執(zhí)行此 console 提示 console.log('Client connected');
          // 對message設置監(jiān)聽,接收從客戶端發(fā)送的消息 ws.on('message', (data) => { //data為客戶端發(fā)送的消息,將消息原封不動返回回去 ws.send(data); });
          // 當WebSocket的連接關閉時執(zhí)行 ws.on('close', () => { console.log('Close connected'); });});
          執(zhí)行node server.js啟動服務,端口打開后會執(zhí)行監(jiān)聽時間打印提示,說明服務啟動成功。



          在開啟WebSocket后,服務端會在message中監(jiān)聽,接收參數(shù)data捕獲客戶端發(fā)送的消息,然后使用send發(fā)送消息

          客戶端接收發(fā)送消息

          分別在根目錄創(chuàng)建index.html和index.js文件
          • index.html
          <html>  <body>    <script src="./index.js">script>  body>html>
          • index.js
          // 使用WebSocket的地址向服務端開啟連接let ws = new WebSocket('ws://localhost:3000');
          // 開啟后的動作,指定在連接后執(zhí)行的事件ws.onopen = () => { console.log('open connection');};
          // 接收服務端發(fā)送的消息ws.onmessage = (event) => { console.log(event);};
          // 指定在關閉后執(zhí)行的事件ws.onclose = () => { console.log('close connection');};
          上面的url就是本機node開啟的服務地址,分別指定連接(onopen),關閉(onclose)和消息接收(onmessage)的執(zhí)行事件,訪問html,打印ws信息。



          打印了open connection說明連接成功,客戶端會使用onmessage處理接收
          其中event參數(shù)包含這次溝通的詳細信息,從服務端回傳的消息會在event的data屬性中。
          手動在控制臺調用send發(fā)送消息,打印event回傳信息:



          服務端定時發(fā)送

          上面是從客戶端發(fā)送消息,服務端回傳。我們也可以通過setInterval讓服務端在固定時間發(fā)送消息給客戶端:
          server.js修改如下:
          //當WebSocket從外部連接時執(zhí)行wss.on('connection', (ws) => {  //連接時執(zhí)行此 console 提示  console.log('Client connected');
          + //固定發(fā)送最新消息給客戶端+ const sendNowTime = setInterval(() => {+ ws.send(String(new Date()));+ }, 1000);
          - //對message設置監(jiān)聽,接收從客戶端發(fā)送的消息- ws.on('message', (data) => {- //data為客戶端發(fā)送的消息,將消息原封不動返回回去- ws.send(data);- });
          //當 WebSocket的連接關閉時執(zhí)行 ws.on('close', () => { console.log('Close connected'); });});
          客戶端連接后就會定時接收,直至我們關閉websocket服務

          多人聊天

          如果多個客戶端連接按照上面的方式只會返回各自發(fā)送的消息,先注釋服務端定時發(fā)送,開啟兩個窗口模擬:
          如果我們要讓客戶端間消息共享,也同時接收到服務端回傳的消息呢?
          我們可以使用clients找出當前所有連接中的客戶端 ,并通過回傳消息發(fā)送到每一個客戶端 中:
          修改server.js如下:
          ...
          //當WebSocket從外部連接時執(zhí)行wss.on('connection', (ws) => { //連接時執(zhí)行此 console 提示 console.log('Client connected');
          - //固定發(fā)送最新消息給客戶端- const sendNowTime = setInterval(() => {- ws.send(String(new Date()));- }, 1000);
          + //對message設置監(jiān)聽,接收從客戶端發(fā)送的消息+ ws.on('message', (data) => {+ //取得所有連接中的 客戶端+ let clients = wss.clients;+ //循環(huán),發(fā)送消息至每個客戶端+ clients.forEach((client) => {+ client.send(data);+ });+ });
          //當WebSocket的連接關閉時執(zhí)行 ws.on('close', () => { console.log('Close connected'); });});
          這樣一來,不論在哪個客戶端發(fā)送消息,服務端都能將消息回傳到每個客戶端 :

          可以觀察下連接信息:


          總結?

          紙上得來終覺淺,絕知此事要躬行,希望大家可以把理論配合上面的實例進行消化,搭好服務端也可以直接使用測試工具好好玩耍一波。



          本文完~
          瀏覽 71
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  动漫足交| 影音先锋在线看片av一区 | 久久亚洲AV成人无码国产电影 | 免费乱伦网站 | 男女操逼在线免费观看 |