<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 可以玩出些什么花兒?

          共 6895字,需瀏覽 14分鐘

           ·

          2022-07-11 22:45


          大家好,我是魚(yú)皮。今天給大家分享一篇 Websocket 實(shí)際使用場(chǎng)景的文章,希望能幫助到大家學(xué)習(xí)和使用 Websocket 。

          一、首先我們要了解 Websocket 握手的原理

          請(qǐng)求頭特征

          • HTTP 必須是 1.1 GET 請(qǐng)求
          • HTTP Header 中 Connection 字段的值必須為 Upgrade
          • HTTP Header 中 Upgrade 字段必須為 websocket
          • Sec-WebSocket-Key 字段的值是采用 base64 編碼的隨機(jī) 16 字節(jié)字符串
          • Sec-WebSocket-Protocol 字段的值記錄使用的子協(xié)議,比如 binary base64
          • Origin 表示請(qǐng)求來(lái)源

          響應(yīng)頭特征

          • 狀態(tài)碼是 101 表示 Switching Protocols
          • Upgrade / Connection / Sec-WebSocket-Protocol 和請(qǐng)求頭一致
          • Sec-WebSocket-Accept 是通過(guò)請(qǐng)求頭的 Sec-WebSocket-Key 生成

          二、短連接輪詢、長(zhǎng)連接、Websocket 橫向?qū)Ρ?/span>

          1. 短連接輪詢

          • 很耗費(fèi) TCP 連接
          • 而且 Header 重復(fù)發(fā)送
          • 且通過(guò)宏任務(wù)發(fā)起,受限于 Event Loop,無(wú)法保證及時(shí)性
          • 同時(shí)無(wú)效請(qǐng)求會(huì)很多

          2. 長(zhǎng)連接

          • HTTP keep-alive 開(kāi)啟后雖然 TCP 可以復(fù)用,但是 Header 重復(fù)的問(wèn)題并沒(méi)有解決
          • 同時(shí) HTTP keep-alive 還有一個(gè)有效期,有效期結(jié)束后服務(wù)端會(huì)發(fā)偵查幀探查 TCP 是否有效

          題外話:

          HTTP keep-alive 的作用是,告知服務(wù)端持久化當(dāng)前的 TCP 連接,不要立即斷開(kāi),以便后續(xù)的 HTTP 請(qǐng)求復(fù)用它,也就是我們所說(shuō)的「長(zhǎng)連接」

          HTTP 的 keep-alive 是為了讓 TCP 活久一點(diǎn),而 TCP 本身也有一個(gè) keepalive(注意沒(méi)有橫杠哦)機(jī)制。這是 TCP 的一種檢測(cè)連接狀況的保活機(jī)制,keepalive 是 TCP 保活定時(shí)器:TCP 建立后,如果閑置沒(méi)用,服務(wù)器不可能白等下去,閑置一段時(shí)間[可設(shè)置]后,服務(wù)器就會(huì)嘗試向客戶端發(fā)送偵測(cè)包,來(lái)判斷 TCP 連接狀況,如果沒(méi)有收到對(duì)方的回答(ACK包),就會(huì)過(guò)一會(huì)[可設(shè)置]再偵測(cè)一次,如果多次[可設(shè)置]都沒(méi)回答,就會(huì)丟棄這個(gè) TCP 連接

          (TCP keepalive 保活示意圖)

          3. Websocket

          • 和 HTTP 一樣都是建立在 TCP 協(xié)議之上,但只需一次 HTTP 握手,就能建立持久性連接,后續(xù)就不走 HTTP 了,而是 WebSocket 特有的數(shù)據(jù)幀
          • 全雙工通信,雙向數(shù)據(jù)傳輸
          • 數(shù)據(jù)格式輕量,且支持發(fā)送二進(jìn)制數(shù)據(jù),支持 ws 和加密的 wss

          三、我在微信小程序中利用 WebSocket 都搗鼓了什么?

          1 驗(yàn)簽鑒權(quán)及對(duì)應(yīng)的容錯(cuò)策略(登錄態(tài)要求、峰值訪問(wèn)、服務(wù)端宕機(jī)異常)

          背景與目的:

          • websocket 握手后,接口請(qǐng)求即可以放棄 HTTP 改走 weboskcet,但大部分業(yè)務(wù)接口都要求登錄態(tài),因此握手成功后必須先走一次簽名鑒權(quán),獲取登錄態(tài)
          • 當(dāng)出現(xiàn)大流量訪問(wèn)的場(chǎng)景(如大促、熱點(diǎn)活動(dòng)等)或服務(wù)端出 bug 而導(dǎo)致服務(wù)端宕機(jī),前端會(huì)做 對(duì)應(yīng)容錯(cuò),將位于內(nèi)存的等待隊(duì)列中的待發(fā)送請(qǐng)求立即降級(jí)成 HTTP 發(fā)送出去

          偽碼示意:

          SocketTask.onOpen(function () {
            SocketTask.sendSocketMessage({
               msg_type: '驗(yàn)簽'
               token: 'xxx'
            }, (response) => {
                console.log(response.user_id, response.access_token)

                // 通道可用,打個(gè)標(biāo)記
                global.isSocketAvaliable = true;
            })
          })

          2 心跳保活(減少 TCP 占用)

          背景與目的:為了減少 TCP 連接的無(wú)效占用,客戶端定時(shí)發(fā)送一個(gè)空包到服務(wù)端,告知服務(wù)端不要銷毀這條 socket,如果服務(wù)端超過(guò)一定時(shí)間都沒(méi)收到心跳包,則將關(guān)閉并銷毀該 socket

          偽碼示意:

          SocketTask.onOpen(function () {
            SocketTask.sendSocketMessage({
               msg_type: '驗(yàn)簽'
               token: 'xxx'
            }, (response) => {
                console.log(response.user_id, response.access_token)

                // 通道可用,打個(gè)標(biāo)記
                global.isSocketAvaliable = true;
                
                // 驗(yàn)簽成功,開(kāi)始定時(shí)發(fā)送心跳包
                setInterval(() => {
                    SocketTask.sendSocketMessage({
                      msg_type: '心跳'
                    });
                });
             });
          })

          3 模擬 RTT(用于弱網(wǎng)體驗(yàn)優(yōu)化)

          背景與目的:在發(fā)送心跳包時(shí),可得知一個(gè)心跳包的 RTT,以此模擬當(dāng)前用戶網(wǎng)絡(luò)環(huán)境的 TCP RTT,并據(jù)此計(jì)算出平滑 RTO,用于弱網(wǎng)體驗(yàn)優(yōu)化

          偽碼示意:

          SocketTask.onOpen(function () {
            SocketTask.sendSocketMessage({
               msg_type: '驗(yàn)簽'
               token: 'xxx'
            }, (response) => {
                console.log(response.user_id, response.access_token)

                // 通道可用,打個(gè)標(biāo)記
                global.isSocketAvaliable = true;
                
                // 驗(yàn)簽成功,開(kāi)始定時(shí)發(fā)送心跳包
                setInterval(() => {
                    // 計(jì)算 RTT
                    const begin = Date.now();

                    SocketTask.sendSocketMessage({
                      msg_type: '心跳'
                    }, () => {
                      const end = Date.now();
                      
                      const RTT = begin - end;
                      
                      const smoothedRTO = cal(RTT);
                      
                      global.smoothedRTO = smoothedRTO;
                    });
                });
             });
          });

          4 Snappy 壓縮(橫向?qū)Ρ攘?gzip / zip / 7z)

          背景與目的:在小程序中引入第三方壓縮包(犧牲小程序包體積),減少 websocket 傳輸?shù)淖止?jié)數(shù)

          偽碼示意:

            import Snappy from 'snappy';

            SocketTask.sendSocketMessage = function (msg) {
               const encryptedMsg = Snappy.encode(msg);
               
               wx.send(encryptedMsg);
            }

          5 重連(階梯式錯(cuò)位重連,避免擁擠)

          背景與目的:用戶的網(wǎng)絡(luò)環(huán)境不穩(wěn)定,可能會(huì)存在主動(dòng) / 被動(dòng)斷開(kāi) socket 的情況,需要進(jìn)行自動(dòng)重連

          偽碼示意:

          SocketTask.onClose(function () {
            // 限定最大重連次數(shù)
            if (retryCount > maxCount) {
              return;
            }
            
            retryCount++;

            setTimeout(() => {
              SocketTask.connectSocket();
            }, retryCount * 1000 + Math.random() * 1000);
          });

          6 埋點(diǎn)中間層緩存(重復(fù)的用戶信息可以不用每次都上報(bào),支持刷新緩存)

          背景與目的:為減少網(wǎng)絡(luò)傳輸?shù)陌w積,通過(guò) websocket 上報(bào)埋點(diǎn)日志時(shí),可以把部分重復(fù)字段值在第一次上報(bào)時(shí)緩存在服務(wù)端,從第二次上報(bào)開(kāi)始只上報(bào)值不重復(fù)的字段,然后由服務(wù)端做日志合并

          偽碼示意:

          SocketTask.sendSocketMessage({
               msg_type: '埋點(diǎn)日志'
               logs: {
                 country: 'China', // 可緩存字段
                 city: '北京', // 可緩存字段
                 platform: '安卓', // 可緩存字段
                 click_some_btn: true // 動(dòng)態(tài)變化的埋點(diǎn)字段
               },
               cacheFields: ['country''city''platform'] // 只在第一次上報(bào)時(shí)攜帶
           });

          7 啟用 TCP_NODELAY

          TCP_NODELAY 是用來(lái)禁用 Nagle 算法的。Nagle 算法設(shè)計(jì)的目的是提高網(wǎng)絡(luò)帶寬利用率,其核心思路是「合并小的 TCP 包為一個(gè)大的 TCP 包」,避免過(guò)多的小包的 TCP 頭部浪費(fèi)網(wǎng)絡(luò)帶寬

          參考資料:https://www.zhihu.com/question/42308970



          以上就是本期分享了。


          最后,歡迎加入 魚(yú)皮的編程知識(shí)星球(點(diǎn)擊了解詳情),和大家一起交流學(xué)習(xí)編程,向魚(yú)皮和大廠同學(xué) 1 對(duì) 1 提問(wèn)、幫你制定學(xué)習(xí)計(jì)劃不迷茫、跟著魚(yú)皮直播做項(xiàng)目(往期項(xiàng)目可無(wú)限回看)、領(lǐng)取魚(yú)皮原創(chuàng)編程學(xué)習(xí)/求職資料等。最近秋招開(kāi)始了,星球內(nèi)也會(huì)幫大家規(guī)劃求職進(jìn)度、完善簡(jiǎn)歷和項(xiàng)目。



          往期推薦

          我是怎么自學(xué) Git / GitHub 的?

          盤(pán)點(diǎn) Vue.js 那些有趣的版本名稱!

          一線前端組長(zhǎng)的 Code Review 分享

          請(qǐng)查收:幾個(gè)實(shí)用的 CSS 小技巧

          前端不哭!web性能優(yōu)化技巧請(qǐng)收好

          瀏覽 41
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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 | 男女靠b的视频网站 | 亚洲男女啪啪视频 | 国产做a爱一级毛片久久 |