简易WebSocket

这是我将要编写的WebSocket系列的第一篇文章,其目标是以最简单的方式解释事物。让我们直接进入它。

WebSockets允许用户使用持久的双向连接向服务器发送和接收消息。基本上,这是客户端服务器之间的通信方式。让我们先了解一下这种通信,稍后我们将回到WebSockets。

客户端和服务器

Web浏览器(客户端)和服务器通过TCP/IP进行通信。超文本传输​​协议(HTTP)是TCP/IP 之上的标准应用程序协议支持请求(来自Web浏览器)及其响应(来自服务器)。

这是如何运作的?

我们来看看这些简单的步骤: -

  1. 客户端向服务器发送请求。
  2. 建立连接。
  3. 服务器发回响应。
  4. 客户端收到响应。
  5. 连接已关闭。

这是对客户端和服务器之间标准通信如何工作的简单概述。现在仔细看看第一步。5。

连接已关闭。

HTTP请求已达到其目的,不再需要它,因此连接已关闭。

如果服务器想要向客户端发送消息,该怎么办?

在我们的标准请求/响应方案中,必须根据开始通信的请求建立连接。如果服务器想要发送消息,则客户端必须发送另一个请求以建立连接并接收消息。

客户端如何知道服务器想要发送消息?

考虑这个例子:
客户饿了,并在网上订购了一些食物。他每秒发出一个请求以检查订单是否准备就绪。

0秒:食物准备好了吗?(客户)
0秒:不,等等。(服务器)
1秒:食物准备好了吗?(客户)
1秒:不,等等。(服务器)
2秒:食物准备好了吗?(客户)
2秒:不,等等。(服务器)
3秒:食物准备好了吗?(客户)
3秒:是的,先生,这是您的订单。(服务器)

这就是你所谓的HTTP轮询。客户端向服务器发出重复请求,并检查是否有任何消息要接收。

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

有没有办法克服这个问题

是的,有一种用于克服这种缺陷的轮询技术,它被称为长轮询(Long Polling)。

Long Polling基本上涉及向服务器发出HTTP请求,然后保持连接打开以允许服务器稍后响应(由服务器确定)。

考虑上面例子的Long-Polling版本: -

0秒:食物准备好了吗?(客户)
3秒:是的,先生,这是您的订单。(服务器)

这样,问题解决了。
不完全是。虽然长轮询工作,但它在CPU,内存和带宽方面非常昂贵(因为我们阻止资源保持连接打开)。

我们现在干什么?看起来事情已经失控。让我们回到我们的救世主:WebSocket

为什么选择WebSockets

如您所见,Polling和Long-Polling都是非常昂贵的选项,以模拟客户端和服务器之间的实时通信。此性能瓶颈是您希望使用WebSocket的原因。

WebSockets不需要您发送请求以进行响应。它们允许双向数据流,因此您只需要监听任何数据。

您可以只听服务器,它会在可用时向您发送消息。

让我们看一下WebSocket的性能方面。

资源消耗

下图显示了一个相对常见的用例中WebSockets与Long Polling之间的带宽消耗差异:

差异很大,并且随着请求的数量呈指数增长。

速度

以下是在一秒内为每个连接提供的1,10和50个请求的结果:

如您所见,使用Socket.io对每个连接发出单个请求的速度要慢50%,因为必须首先建立连接。这种开销较小,但对于十个请求仍然很明显。在来自同一连接的50个请求中,Socket.io已经快50%。为了更好地了解峰值吞吐量,我们将查看基准测试,每个连接的请求数量更多(500,1000和2000):

在这里,您可以看到HTTP基准峰值约为每秒约950个请求,而Socket.io每秒约为3900个请求。有效,对吗?

注意:Socket.io是用于实时Web应用程序的JavaScript库。它在内部实现WebSocket。将此视为WebSocket的包装器,它提供了更多功能(本系列的下一篇博客文章详细介绍了Socket.io

WebSockets如何工作

这些是建立WebSocket连接所涉及的步骤。

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

我们将创建两个文件:一个服务器和一个客户端。
首先,创建一个<html>名为client.html包含<script>标记的简单文档。让我们看看它的外观: -

Client.html

<html>

<script>
    // Our code goes here
</script>

<body>
    <h1>This is a client page</h1>
</body>

</html>

Server.js

现在创建另一个文件server.js。导入HTTP模块并创建服务器。让它听port 8000

这将作为一个简单的http服务器监听port 8000。让我们看一下:

//importing http module
const http = require('http');

//creating a http server
const server = http.createServer((req, res) => {
    res.end("I am connected");
});

//making it listen to port 8000
server.listen(8000);

运行命令node server.js开始监听port 8000您可以根据需要选择任何端口,我只是选择了8000无特殊原因。

我们现在完成了客户端和服务器的基本设置。那很简单,对吧?让我们现在就开始吧。

客户端设置

要构造WebSocket,请使用WebSocket()返回websocket对象的构造函数。此对象提供用于创建和管理与服务器的WebSocket连接的API 。

简单来说,这个websocket对象将帮助我们建立与服务器的连接并创建双向数据流,即从两端发送和接收数据

让我们看看如何:

<html>

<script>
    //calling the constructor which gives us the websocket object: ws
    let ws = new WebSocket('url'); 
</script>

<body>
    <h1>This is a client page</h1>
</body>

</html>
      

WebSocket构造函数需要一个URL来听。在我们的例子中,这是'ws://localhost:8000'因为我们的服务器正在运行。
现在,这可能与您习惯的有点不同。我们没有使用HTTP协议,我们正在使用WebSocket协议。这会告诉客户“嘿,我们使用WebSocket协议”,因此'ws://'代替'http://'。够简单吗?现在让我们实际创建一个WebSocket服务器server.js

服务器设置

我们将ws在节点服务器中使用第三方模块来使用和设置WebSocket服务器。

首先,我们将导入ws模块。然后我们将创建一个websocket服务器并将其HTTP交给服务器监听port 8000

HTTP服务器正在侦听端口8000,WebSocket服务器正在侦听此HTTP服务器。基本上,这就是监听者。

现在我们的websocket正在关注流量port 8000。这意味着它将在客户端可用时立即尝试建立连接。我们的server.js文件看起来像这样:

const http = require('http');
//importing ws module
const websocket = require('ws');

const server = http.createServer((req, res) => {
    res.end("I am connected");
});
//creating websocket server
const wss = new websocket.Server({ server });

server.listen(8000);

正如我们之前讨论的那样 - WebSocket()构造函数返回一个websocket对象,提供用于创建和管理与服务器的WebSocket连接的API 。

在这里,wss对象将帮助我们Event在某些事情发生时听取发出的声音。就像建立连接或握手完成或连接关闭等。

让我们看看如何收听消息:

const http = require('http');
const websocket = require('ws');

const server = http.createServer((req, res) => {
    res.end("I am connected");
});
const wss = new websocket.Server({ server });
//calling a method 'on' which is available on websocket object
wss.on('headers', (headers, req) => {
    //logging the header
    console.log(headers);
});

server.listen(8000);

该方法'on'需要两个参数:事件名称和回调。事件名称是我们想要监听/发出的,回调指定了如何处理它。在这里,我们只是记录headers事件。让我们看看我们得到了什么:

这是我们的HTTP标题,我希望你对它好奇,因为这正是幕后发生的事情。让我们分解它以更好地理解它。

  • 您会注意到的第一件事是我们获得了状态代码101。您可能已经看到200201404状态代码,但这个看起来不一样。101实际上是切换协议状态代码。它说“嘿,我想升级”
  • 第二行显示升级信息。它指定它要升级到websocket协议。
  • 这实际上是握手期间发生的事情。浏览器使用HTTP使用建立连接的连接HTTP/1.1协议,然后将其Upgradewebsocket协议。

现在这将更有意义。

Headers响应标头被写入到插座作为握手的一部分之前被发射事件。这允许您在发送标头之前检查/修改标头。这意味着您可以根据需要修改标题以接受,拒绝或其他任何内容。默认情况下,它接受请求。

同样,我们可以添加一个connection在握手完成时发出的事件。成功建立连接后,我们将向客户端发送消息。我们来看看如何:

const http = require('http');
const websocket = require('ws');

const server = http.createServer((req, res) => {
    res.end("I am connected");
});
const wss = new websocket.Server({ server });

wss.on('headers', (headers, req) => {
    //console.log(headers); Not logging the header anymore
});

//Event: 'connection'
wss.on('connection', (ws, req) => {
    ws.send('This is a message from server, connection is established');
    //receive the message from client on Event: 'message'
    ws.on('message', (msg) => {
        console.log(msg);
    });
});

server.listen(8000);

我们也在听取message客户的意见。让我们创造: -

<html>

<script>
    let ws = new WebSocket('url'); 
    //logging the websocket property properties
    console.log(ws);
    //sending a message when connection opens
    ws.onopen = (event) => ws.send("This is a message from client");
    //receiving the message from server
    ws.onmessage = (message) => console.log(message);
</script>

<body>
    <h1>This is a client page</h1>
</body>

</html>

这就是它在浏览器中的外观: -

第一个日志WebSocket列出了websocket对象上的所有属性,第二个日志列出MessageEventdata属性。如果仔细观察,您会看到我们从服务器收到了消息。

服务器日志将如下所示:

我们正确地收到了客户的消息。这标志着我们的连接成功建立。干杯吧!

结论

总结一下,让我们来看看我们学到的东西:

  • 我们已经介绍了HTTP服务器的工作原理,什么是Polling,Long Polling。
  • 什么是WebSockets以及我们为什么需要它们。
  • 我们介绍了他们如何在幕后工作,并更好地理解所使用的标题。
  • 我们创建了自己的客户端和服务器,并成功建立了它们之间的连接。

这是WebSockets的基础知识及其工作原理。本系列的下一篇文章socket.io将更详细地介绍和使用它。我们还将看到为什么socket.io当事情与唯一的本地人一起工作时我们确切需要WebSocket()。当我们成功发送和接收消息时,为什么要使用臃肿的库?

如果您觉得它有用,请分享这篇文章并继续关注下一篇文章。
沙德。

参考

转:https://levelup.gitconnected.com/websocket-simplified-b532f266cc9f

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容