1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        5000字!帶你零距離接觸websocket!

        共 5360字,需瀏覽 11分鐘

         ·

        2020-10-08 18:15

        作者@johnYu

        原文?https://juejin.im/post/6876301731966713869

        排版 執(zhí)行上下文

        1、什么是WebSocket?

        1.1、定義

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

        1.2、關(guān)聯(lián)和區(qū)別

        1.2.1、HTTP

        1、HTTP是非持久的協(xié)議,客戶端想知道服務(wù)端的處理進度只能通過不停地使用 Ajax進行輪詢或者采用 long poll 的方式來,但是前者對服務(wù)器壓力大,后者則會因為一直等待Response造成阻塞。

        2、雖然http1.1默認(rèn)開啟了keep-alive長連接保持了這個TCP通道使得在一個HTTP連接中,可以發(fā)送多個Request,接收多個Response,但是一個request只能有一個response。而且這個response也是被動的,不能主動發(fā)起。

        3、websocket雖然是獨立于HTTP的一種協(xié)議,但是websocket必須依賴 HTTP 協(xié)議進行一次握手(在握手階段是一樣的),握手成功后,數(shù)據(jù)就直接從 TCP通道傳輸,與 HTTP 無關(guān)了,可以用一張圖理解兩者有交集,但是并不是全部。

        1.2.2、socket

        1、socket也被稱為套接字,與HTTP和WebSocket不一樣,socket不是協(xié)議,它是在程序?qū)用嫔蠈鬏攲訁f(xié)議(可以主要理解為TCP/IP)的接口封裝。可以理解為一個能夠提供端對端的通信的調(diào)用接口(API)

        2、對于程序員而言,其需要在 A 端創(chuàng)建一個 socket 實例,并為這個實例提供其所要連接的 B 端的 IP 地址和端口號,而在 B 端創(chuàng)建另一個 socket 實例,并且綁定本地端口號來進行監(jiān)聽。當(dāng) A 和 B 建立連接后,雙方就建立了一個端對端的 TCP 連接,從而可以進行雙向通信。WebSocekt借鑒了 socket 的思想,為 client 和 server 之間提供了類似的雙向通信機制。

        1.3、應(yīng)用場景

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

        1.3.1、Websocket握手

        //?Websocket握手請求報文??????

        GET?/chat?HTTP/1.1
        Host:?server.example.com
        Upgrade:websocket
        Connection:?Upgrade
        Sec-WebSocket-Key:?x3JJHMbDL1EzLkh9GBhXDw==
        Sec-WebSocket-Protocol:?chat,?superchat
        Sec-WebSocket-Version:?13
        Origin:?http://example.com

        下面是與傳統(tǒng) HTTP 報文不同的地方:

        Upgrade:?websocket
        Connection:?Upgrade

        表示發(fā)起的是 WebSocket 協(xié)議

        Sec-WebSocket-Key:?x3JJHMbDL1EzLkh9GBhXDw==
        Sec-WebSocket-Protocol:?chat,?superchat
        Sec-WebSocket-Version:?13

        Sec-WebSocket-Key 是由瀏覽器隨機生成的,驗證是否可以進行Websocket通信,防止惡意或者無意的連接。

        Sec_WebSocket-Protocol 是用戶自定義的字符串,用來標(biāo)識服務(wù)所需要的協(xié)議

        Sec-WebSocket-Version 表示支持的 WebSocket 版本。

        //?服務(wù)器響應(yīng):?????

        HTTP/1.1?101?Switching?Protocols
        Upgrade:?websocket
        Connection:?Upgrade
        Sec-WebSocket-Accept:?HSmrc0sMlYUkAGmm5OPpG2HaGWk=
        Sec-WebSocket-Protocol:?chat

        101 響應(yīng)碼 表示要轉(zhuǎn)換協(xié)議。

        Connection: Upgrade 表示升級新協(xié)議請求。

        Upgrade: websocket 表示升級為 WebSocket 協(xié)議。

        Sec-WebSocket-Accept 是經(jīng)過服務(wù)器確認(rèn),并且加密過后的

        Sec-WebSocket-Key 用來證明客戶端和服務(wù)器之間能進行通信了。

        Sec-WebSocket-Protocol 表示最終使用的協(xié)議。

        至此,客戶端和服務(wù)器握手成功建立了Websocket連接,HTTP已經(jīng)完成它所有工作了,接下來就是完全按照Websocket協(xié)議進行通信了。

        2、關(guān)于Websocket

        2.1、WebSocket心跳

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

        2.2、WebSocket狀態(tài)

        WebSocket 對象中的readyState屬性有四種狀態(tài):

        0:?表示正在連接
        1:?表示連接成功,可以通信了
        2:?表示連接正在關(guān)閉
        3:?表示連接已經(jīng)關(guān)閉,或者打開連接失敗

        2.3、WebSocket實踐

        2.3.1、服務(wù)端接收發(fā)送消息

        WebSocket的服務(wù)端部分,本文會以Node.js搭建。

        安裝express和負責(zé)處理WebSocket協(xié)議的ws

        npm?install?express?ws
        安裝成功后的package.json:
        接著在根目錄創(chuàng)建server.js文件:
        //?引入express?和?ws
        const?express?=?require('express');
        const?SocketServer?=?require('ws').Server;

        //?指定開啟的端口號const?PORT?=?3000;
        //?創(chuàng)建express,綁定監(jiān)聽3000端口,且設(shè)定開啟后在consol中提示
        const?server?=?express().listen(PORT,?()?=>?console.log(`Listening?on?${PORT}`));

        //?將express交給SocketServer開啟WebSocket的服務(wù)
        const?wss?=?new?SocketServer({?server?});

        //?當(dāng)?WebSocket?從外部連接時執(zhí)行
        wss.on('connection',?(ws)?=>?{

        ????//?連接時執(zhí)行此?console?提示?console.log('Client?connected');
        ????//?對message設(shè)置監(jiān)聽,接收從客戶端發(fā)送的消息?
        ????ws.on('message',?(data)?=>?{
        ????
        ????????//?data為客戶端發(fā)送的消息,將消息原封不動返回回去
        ????????ws.send(data);
        ????});
        ????
        ????//?當(dāng)WebSocket的連接關(guān)閉時執(zhí)行
        ????ws.on('close',?()?=>?{
        ????????console.log('Closeconnected');
        ????});
        });
        執(zhí)行node server.js啟動服務(wù),端口打開后會執(zhí)行監(jiān)聽時間打印提示,說明服務(wù)啟動成功。
        在開啟WebSocket后,服務(wù)端會在message中監(jiān)聽,接收參數(shù)data捕獲客戶端發(fā)送的消息,然后使用send發(fā)送消息。

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

        分別在根目錄創(chuàng)建index.html和index.js文件
        //?index.html


        ??
        ????
        ??

        //?index.js

        //?使用WebSocket的地址向服務(wù)端開啟連接
        let?ws?=?new?WebSocket('ws://localhost:3000');

        //?開啟后的動作,指定在連接后執(zhí)行的事件
        ws.onopen?=?()?=>?{
        ????console.log('open?connection');
        };

        //?接收服務(wù)端發(fā)送的消息
        ws.onmessage?=?(event)?=>?{
        ????console.log(event);
        };

        //?指定在關(guān)閉后執(zhí)行的事件
        ws.onclose?=?()?=>?{
        ????console.log('close?connection');
        };

        上面的url就是本機node開啟的服務(wù)地址,分別指定連接 (onopen),關(guān)閉 (onclose) 和消息接收 (onmessage) 的執(zhí)行事件,訪問html,打印ws信息。

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

        2.3.3、服務(wù)端定時發(fā)送

        上面是從客戶端發(fā)送消息,服務(wù)端回傳。我們也可以通過setInterval讓服務(wù)端在固定時間發(fā)送消息給客戶端:
        //?server.js修改如下:

        //?當(dāng)WebSocket從外部連接時執(zhí)行
        wss.on('connection',?(ws)?=>?{

        ????//?連接時執(zhí)行此?console?提示
        ????console.log('Client?connected');
        ????
        ????//?固定發(fā)送最新消息給客戶端
        ????const?=?sendNowTime?=?setInterval(()?=>?{
        ????????ws.send(String(new?Date()));
        ????},?1000);
        ????
        ????//?對message設(shè)置監(jiān)聽,接收從客戶端發(fā)送的消息
        ????ws.on('message',?(data)?=>?{
        ????
        ????????//?data為客戶端發(fā)送的消息,將消息原封不動返回回去
        ????????ws.send(data);
        ????});
        ????
        ????//?當(dāng)WebSocket的連接關(guān)閉時執(zhí)行
        ????ws.on('close',()?=>?{
        ????????console.log('Close?connected');
        ????});
        });
        客戶端連接后就會定時接收,直至我們關(guān)閉websocket服務(wù)。

        2.3.4、多人聊天

        如果多個客戶端連接按照上面的方式只會返回各自發(fā)送的消息,先注釋服務(wù)端定時發(fā)送,開啟兩個窗口模擬:

        如果我們要讓客戶端間消息共享,也同時接收到服務(wù)端回傳的消息呢?

        我們可以使用clients找出當(dāng)前所有連接中的客戶端 ,并通過回傳消息發(fā)送到每一個客戶端中:

        修改server.js如下:
        //當(dāng)WebSocket從外部連接時執(zhí)行
        wss.on('connection',?(ws)?=>?{

        ????//連接時執(zhí)行此?console?提示
        ????console.log('Client?connected');
        ????
        ????//固定發(fā)送最新消息給客戶端
        ????const?sendNowTime?=?setInterval(()?=>?{
        ????????ws.send(String(new?Date()));
        ????},?1000);

        ????//對message設(shè)置監(jiān)聽,接收從客戶端發(fā)送的消息
        ????ws.on('message',?(data)?=>?{
        ????
        ????????//取得所有連接中的?客戶端
        ????????let?clients?=?wss.clients;
        ????????
        ????????//循環(huán),發(fā)送消息至每個客戶端
        ????????clients.forEach((client)?=>?{
        ????????????client.send(data);
        ????????});
        ????});

        ????//當(dāng)WebSocket的連接關(guān)閉時執(zhí)行
        ????ws.on('close',?()?=>?{
        ????????console.log('Close?connected');
        ????});
        });
        這樣一來,不論在哪個客戶端發(fā)送消息,服務(wù)端都能將消息回傳到每個客戶端:
        可以觀察下連接信息:

        3、總結(jié) ?

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


        ??愛心三連擊

        1.看到這里了就點個在看支持下吧,你的點贊在看是我創(chuàng)作的動力。

        2.關(guān)注公眾號程序員成長指北,回復(fù)「1」加入Node進階交流群!「在這里有好多 Node 開發(fā)者,會討論 Node 知識,互相學(xué)習(xí)」!

        3.也可添加微信【ikoala520】,一起成長。


        “在看轉(zhuǎn)發(fā)”是最大的支持

        瀏覽 43
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日本无码一区二区三三 | 爱搞在线播放 | 成人做爰A片100部免费 | 黑人鸡巴视频 | 欧美第一作坊视频平台2020欧美 | 美女掰开逼 | 欧美999 | 东京热一区二区三区四区 | 欧美成人网站免费在线观看 | 亚洲无吗在线 |