草庐IT

【WebSocket 协议】Web 通信的下一步进化

我想养只猫 •͓͡•ʔ 2023-09-09 原文

标题【手动狗头🐶】,大佬轻饶



目录



WebSocket 是基于单个 TCP 的双向计算机通信协议。

你可以在简单的谷歌、百度搜索中找到许多类似的定义,但是我想通过一些简单和明显的例子来说明这这些。



一、什么是 WebSocket ?

作为 HTML5 计划的一部分,开发的 WebSocket 规范引入了 WebSocket JavaScript 接口,该接口定义了一个全双工单套接字连接,通过该连接可以在客户端和服务器之间发送消息。

WebSocket 标准简化了双向 Web 通信和连接管理的大部分复杂性。

CometAjax 相比,WebSocket 代表了 Web 通信的下一个进化步骤。当然每种技术都有其独特的功能。

WebSocketws://wss:// 开始。它是一个有状态的协议,这意味着客户端和服务器之间的连接将保持活动状态,直到它被任何一方(客户端或服务器)终止。客户端和服务器中的任何一个关闭连接后,连接都会从两端终止。

让我们举一个客户端与服务器通信的例子,客户端是一个网络浏览器,每当我们启动客户端和服务器之间的连接时,客户端与服务器进行握手并决定创建一个新的连接和这个连接将保持活动状态,直到被其中任何一个终止。当连接建立并处于活动状态时,通信将使用相同的连接通道进行,直到终止。

以下就是 WebSocket 连接所涉及的步骤。

  1. 客户端(浏览器)向服务器发送 HTTP 请求。
  2. 通过 HTTP 协议建立连接。
  3. 如果服务器支持 WebSocket 协议,则同意升级连接。(握手)
  4. 现在握手已经完成,初始 HTTP 连接被使用相同底层 TCP/IP 协议的 WebSocket 连接替换。
  5. 此时,数据可以在 ClientServer 之间自由来回流动。


二、WebSocket 应用场景?

首先,在不使用 WebSocket 的情况下访问网站。 网页通常通过 HTTP 连接在 Internet 上传输。为此客户端会为您执行的每个操作向服务器发出请求。使用 HTTP 访问网站时,客户端必须先向服务器提交请求。然后服务器通过发送请求的连接来响应。换句话说,HTTP 在基本的请求和响应架构上运行,会导致大量延迟。

我举一个实在点的例子:

我们平时点外卖

0秒:食物到了吗?(客户)
0秒:正在配送。(外卖小哥)
1秒:食物到了吗?(客户)
1秒:正在配送。(外卖小哥)
2秒:食物到了吗?(客户)
2秒:正在配送。(外卖小哥)
3秒:食物到了吗?(客户)
3秒:是的,先生,这是您的外卖。(外卖小哥)

这就是我们常见的所说的 HTTP 轮询

客户端向服务器重复请求并检查是否有任何消息要接收。

如您所见,这不是很有效。我们正在使用不必要的资源,失败的请求数量也很麻烦。

有没有办法克服这个问题?

是的,有一种轮询技术可以用来克服这个缺陷,它被称为 长轮询。即:长轮询基本上涉及向服务器发出 HTTP 请求,然后保持连接打开以允许服务器稍后响应(由服务器确定)。

长轮询版本:

0秒:食物到了吗?(客户)
3秒:是的,先生,这是您的外卖。(外卖小哥)

尽管长轮询有效,但它在 CPU、内存和带宽方面消耗的非常高(因为我们在保持连接打开时阻塞了资源)。

那么我们的救星就是:WebSocket

WebSocket 协议的情况有所不同,可以使用动态调用方法实时调用。客户端所要做的就是通过传输 WebSocket 协议的握手来与服务器建立连接。这种握手提供了数据传输所需的所有识别信息。

客户端(Web 浏览器)初始化连接,并定期发送“心跳”以告诉服务器连接始终处于活动状态,一旦建立连接,客户端和服务器(与 http 规范相反)可以向对方发送信息(也称为服务器推送)。

这也与客户端驱动的 xmlhttprequest (ajax) 不同:客户端询问服务器它的状态是否是最新的,如果不是则更新,握手后通道保持打开状态,以实现近乎恒定的通信。

这意味着服务器可以自行传递数据,而无需客户端请求。因此,如果服务器接收到新数据,它会将其传递给客户端,而无需客户端发出特殊请求。

是不是特别好?所以应用场景也就很明显了

  • 聊天程序
  • 社交平台
  • 网络游戏

  • 所有凡是需要客户端与服务端实时通信的场景都可以使用


三、代码中的 WebSocket

对于 WebSocket 代码的实现,我们只需要 (编程语言或者框架名 + WebSocket) 关键词搜索引擎检索一下 就可以实现

以下为不完整统计!仅供参考~

WebSocket 目前支持以下浏览器:

  • Internet Explorer:版本 10 或更高版本
  • Firefox:版本 6 或更高版本
  • Chrome:版本 14 或更高版本
  • Opera:版本 12.10 或更高版本
  • Safari:版本 6 或更高版本

在服务器端,WebSocket 可以与以下编程语言和框架一起使用:

  • Node.js
    • Socket.IO
    • WebSocket-Node
    • ws
  • Java
    • Jetty
  • Python
    • pyWebSocket
    • Tornado
  • C++
    • Libwebsockets


四、一个完美的案例:在线聊天程序

服务端: node.js
前端: html+css+javascript


实现服务器

让我们开始写服务器代码
首先,创建一个名为chat的文件夹。进入此文件夹并通过在终端中输入 npm init
初始化项目,或者 yarn init 。 现在我们已经初始化了我们的应用程序。

我们需要准备两个包

npm install ws serve-handler

这里的 ws 它是 Node.js 的纯 WebSocket 实现。

根目录的 package.json 中记得加入 "type": "module"

chat/index.js

import {createServer} from 'http';
import staticHandler from 'serve-handler';
import ws, {WebSocketServer} from 'ws';

// 创建服务
const server = createServer((req, res) => {
    return staticHandler(req, res, {public: 'public'})
});

// 创建一个WebSocket服务器
const wss = new WebSocketServer({server})

// 当有新的连接时
wss.on('connection', (client) => {
    // 客户端连接
    console.log('Client connected !')
    client.on('message', (msg) => {
        // 客户端发送消息
        console.log(`Message:${msg}`);
        broadcast(msg)
    })
})

// 发送消息
function broadcast(msg) {
    for (const client of wss.clients) {
        if (client.readyState === ws.OPEN) {
            client.send(msg)
        }
    }
}

server.listen(process.argv[2] || 8080, () => {
    console.log(`server listening...`);
})


实现客户端

接下来,是时候实现我们的聊天应用程序的客户端了。本质上是一个带有一些基本 JavaScript 代码的最小 HTML 页面。


chat/index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="style.css">
        <title>聊天室</title>
    </head>
    <body>
        <div class="container">
            <p class="msg">消息:</p>
            <div id="messages" class="messages"></div>
            <form id="msgForm" class="msgForm">
                <input type="text" placeholder="Send message" class="input" id="inputBox"/>
                <input type="submit" class="btn" value="发送">
            </form>
        </div>
        <script type="text/javascript">
            // 初始化
            const ws = new WebSocket(`ws://localhost:8000`);

            ws.binaryType = "blob";

            // 连接成功
            ws.addEventListener("open", event => {
                console.log("Websocket 连接打开");
            });
            // 关闭连接
            ws.addEventListener("close", event => {
                console.log("Websocket 连接关闭");
            });

            // 消息事件
            ws.onmessage = function (message) {
                const msgDiv = document.createElement('div');
                msgDiv.classList.add('msgCtn');
                // 获取消息
                if (message.data instanceof Blob) {
                    reader = new FileReader();
                    // 接收到消息时触发
                    reader.onload = () => {
                        msgDiv.innerHTML = reader.result;
                        document.getElementById('messages').appendChild(msgDiv);
                    };
                    // 读取消息
                    reader.readAsText(message.data);
                } else {
                    // 显示消息
                    console.log("Result2: " + message.data);
                    msgDiv.innerHTML = message.data;
                    document.getElementById('messages').appendChild(msgDiv);
                }
            }
            // 发送消息
            const form = document.getElementById('msgForm');
            form.addEventListener('submit', (event) => {
                event.preventDefault();
                const message = document.getElementById('inputBox').value;
                // 发送
                ws.send(message);
                document.getElementById('inputBox').value = ''
            })
        </script>
    </body>
</html>

chat/style.css

接下来我们让页面变的好看一点

html {
    font-size: 62%;
}

body {
    margin: 0;
    padding: 0;
    display: flex;
    justify-content: center;
}

.container {
    margin-top: 5rem;
    display: flex;
    flex-direction: column;
    width: 30%;
    height: 70vh;
}

.msg {
    color: blueviolet;
    font-size: 2rem;
}

.msgCtn {
    margin: 1rem 0;
    color: white;
    padding: 1rem 1rem;
    background-color: blueviolet;
    border-radius: 6px;
    font-size: 2rem
}

.msgForm {
    display: flex;
    flex-direction: row;
}

.input {
    height: 100%;
    flex: 4;
    margin-right: 2rem;
    border: none;
    border-radius: .5rem;
    padding: 2px 1rem;
    font-size: 1.5rem;
    background-color: aliceblue;
}

.input:focus {
    background-color: white;
}

.btn {
    height: 5rem;
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: .5rem;
    background-color: blueviolet;
    color: whitesmoke;
    border: none;
    font-size: 1.6rem;
}


最终效果

让我们运行

node index.js 8000

然后运行 index.html 这个就不多描述了

打开两个窗口,效果如下:







有关【WebSocket 协议】Web 通信的下一步进化的更多相关文章

  1. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  2. 报告回顾丨模型进化狂飙,DetectGPT能否识别最新模型生成结果? - 2

    导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri

  3. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  4. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  5. ruby - 如何配置 Ruby Mechanize 代理以通过 Charles Web 代理工作? - 2

    我正在使用Ruby/Mechanize编写一个“自动填写表格”应用程序。它几乎可以工作。我可以使用精彩CharlesWeb代理以查看服务器和我的Firefox浏览器之间的交换。现在我想使用Charles查看服务器和我的应用程序之间的交换。Charles在端口8888上代理。假设服务器位于https://my.host.com。.一件不起作用的事情是:@agent||=Mechanize.newdo|agent|agent.set_proxy("my.host.com",8888)end这会导致Net::HTTP::Persistent::Error:...lib/net/http/pe

  6. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  7. ruby - HTTP POST 上的 SSL 错误(未知协议(protocol)) - 2

    尝试通过SSL连接到ImgurAPI时出现错误。这是代码和错误:API_URI=URI.parse('https://api.imgur.com')API_PUBLIC_KEY='Client-ID--'ENDPOINTS={:image=>'/3/image',:gallery=>'/3/gallery'}#Public:Uploadanimage##args-Theimagepathfortheimagetoupload#defupload(image_path)http=Net::HTTP.new(API_URI.host)http.use_ssl=truehttp.verify

  8. 物联网MQTT协议详解 - 2

    一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su

  9. C/C++好用的websocket库 - 2

    IntrductionLibwebsocketsisasimple-to-use,MIT-license,pureClibraryprovidingclientandserverforhttp/1,http/2,websockets,MQTTandotherprotocolsinasecurity-minded,lightweight,configurable,scalableandflexibleway.It’seasytobuildandcross-buildviacmakeandissuitablefortasksfromembeddedRTOSthroughmasscloudservi

  10. 适用于Web开发的Python还是Ruby? - 2

    Asitcurrentlystands,thisquestionisnotagoodfitforourQ&Aformat.Weexpectanswerstobesupportedbyfacts,references,orexpertise,butthisquestionwilllikelysolicitdebate,arguments,polling,orextendeddiscussion.Ifyoufeelthatthisquestioncanbeimprovedandpossiblyreopened,visitthehelpcenter提供指导。11年前关闭。我是一位精通HTML

随机推荐