前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Websocket 研究 / Nodejs 模块选型对比

Websocket 研究 / Nodejs 模块选型对比

原创
作者头像
唐昌林
修改2017-07-25 16:02:52
5K2
修改2017-07-25 16:02:52
举报
文章被收录于专栏:唐昌林的专栏

导语 对Websocket的基础原理研究,并在nodejs的WebSocket库中进行选型对比,选出最适合我们的库。本文分为两章,第一张对WebSocket基础原理进行研究,第二章将从Nodejs库中选出最适合的WebSocket库。

第一章:Websocket研究

WebSocket连接本质上是TCP连接,在网页打开后通过http协议握手之后建立长连接。真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力

WebSocket的生命周期

分为三个阶段:

第一阶段:由客户端发起的握手阶段,握手后建立连接 第二阶段:数据交换,客户端与服务端可以互相主动发送消息 第三阶段:关闭连接,可以由任意一端发起关闭的命令

WebSocket的握手协议

握手请求
代码语言:javascript
复制
GET http://localhost:8181/ HTTP/1.1
Host: localhost:8181
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://tomcltang.kf0309.3g.qq.com
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Sec-WebSocket-Key: VCPIDS4ggndDGQmpLfzMLA==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
  • HTTP request method 必须是GET,协议应不小于1.1
  • Upgrade,并且其值为 websocket;
  • Connection,并且其值为Upgrade;
  • Sec-WebSocket-Key,其值采用base64编码的随机16字节长的字符序列;
  • Origin,服务器可以从Origin决定是否接受该WebSocket连接;
  • Sec-webSocket-Version,当前值必须是13;握手响应
代码语言:javascript
复制
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: UFCeZ5AiDPquwYZOEHuNHBnbZ94=
Sec-WebSocket-Extensions: permessage-deflate
  • 首行返回的是HTTP/1.1协议版本和状态码101,表示变换协议(Switching Protocol)
  • Upgrade,其值为 websocket;
  • Connection,其值为Upgrade;
  • Sec-WebSocket-Accept,加密处理后的握手Key消息体组成

WebSocket的消息并非没有额外信息,除了业务数据以外,消息体也包含一些额外信息。只不过相对http的头会小很多,一般只有6个bytes

FIN:1 bit 指示这个是消息的最后片段。第一个片段可能也是最后的片段。

RSV1, RSV2, RSV3: 每个1 bit 必须是0,除非一个扩展协商为非零值定义含义。如果收到一个非零值且没有协商的扩展定义这个非零值的含义,接收端点必须失败WebSokcket连接。

Opcode: 4 bits 定义了“负载数据”的解释。如果收到一个未知的操作码,接收端点必须失败WebSocket连接。定义了以下值。 %x0 代表一个继续帧 %x1 代表一个文本帧 %x2 代表一个二进制帧 %x3-7 保留用于未来的非控制帧 %x8 代表连接关闭 %x9 代表ping %xA 代表pong %xB-F 保留用于未来的控制帧

Mask: 1 bit 定义是否“负载数据”是掩码的。如果设置为1,一个掩码键出现在masking-key,且这个是用于根据5.3节解掩码(unmask)“负载数据”。从客户端发送到服务器的所有帧有这个位设置为1。

Payload length: 7 bits, 7+16 bits, 或者 7+64 bits “负载数据”的长度,以字节为单位:如果0-125,这是负载长度。如果126,之后的两字节解释为一个16位的无符号整数是负载长度。如果127,之后的8字节解释为一个64位的无符号整数(最高有效位必须是0)是负载长度。多字节长度数量以网络字节顺序来表示。注意,在所有情况下,最小数量的字节必须用于编码长度,例如,一个124字节长的字符串的长度不能被编码为序列126,0,124。负载长度是“扩展数据”长度+“应用数据”长度。“扩展数据”长度可能是零,在这种情况下,负载长度是“应用数据”长度。

Masking-key: 0 or 4 bytes 客户端发送到服务器的所有帧通过一个包含在帧中的32位值来掩码。如果mask位设置为1,则该字段存在,如果mask位设置为0,则该字段缺失。详细信息请参见5.3节 客户端到服务器掩码。

Payload data: (x+y) bytes “负载数据”定义为“扩展数据”连接“应用数据”。

Extension data: x bytes “扩展数据”是0字节除非已经协商了一个扩展。任何扩展必须指定“扩展数据”的长度,或长度是如何计算的,以及扩展如何使用必须在打开阶段握手期间协商。 如果存在,“扩展数据”包含在总负载长度中。

Application data: y bytes 任意的“应用数据”,占用“扩展数据”之后帧的剩余部分。“应用数据”的长度等于负载长度减去“扩展数据”长度。

FIN + RSV1 + RSV2 + RSV3 + Opcode + Mask + Payload length + Masking-key = 业务数据以外的消息大小 1bit + 1bit + 1bit + 1bit + 4bit + 1bit + 7bit + 4bytes = 6bytes

与http对比

以发送JSON字符串 {“req”:”123”} 为例,字符串本身13 bytes 通过http发送的话,http消息总大小 523+13 通过WebSocket发送的话,消息总大小是 6+13

第二章:Nodejs 的Websocket模块选型

由于工作原因,主要用Nodejs进行开发,因此只对比Nodejs实现的WebSocket库 GitHub上面,用nodejs实现的WebSocket库非常多,我挑选了几个靠前的库进行对比

本地Windows环境,对比Ajax与WebSocket发送消息的耗时。可以看到WebSocket的耗时远远低于Ajax

本地Windows环境 不同消息大小的耗时对比库对比

本地Windows环境,处理不同消息大小的耗时对比。 测试结果: websocket-node < faye < ws < socket.io

因为本地Windows环境与生产环境并不一样,因此上面的数据仅作Windows环境参考。因为下面在生产环境进行对比后,数据会有较大差异

以下生产环境测试,都是在2G内存、10个ecu环境下进行的测试对比

生产linux环境 不同消息大小的耗时对比库对比

这个测试与上一个Windows测试是一样的,但结果完全不同。ws表现最好 测试结果:ws< socket.io < websocket-node < faye < ajax

生产linux环境 测试内存波动

使用同样大小的消息,对服务发起大量的请求。测试服务的内存消耗。socket.io/ws/websocket-node 表现都不错,比较稳定。faye表现最差,占用内存高。 测试结果:socket.io < ws < websocket-node < faye

生产linux环境 测试CPU波动

使用同样大小的消息,对服务发起大量的请求。测试服务的CPU占用情况。socket.io表现最差,CPU占比很高。 测试结果:websocket-node = faye < ws < socket.io

生产linux环境 测试最大连接数

在2G内存的服务器上,测试各个库的最大连接数。最好的结果也是差异巨大。最好的ws是最差的socket.io的近三倍 测试结果:ws > websocket-node > faye > socket.io

websocket-node 在连接数超过140000的时候,连接速度比较慢。服务器没响应,但之前的连接不会断开 而faye和ws在到极限的时候,会出现异常。所有连接会断开 socket.io 连接在20000左右 的时候,就非常慢了

生产linux环境 测试最大连接数时的内存与CPU波动

测试最大连接数的时候,同时监控了内存和CPU的波动。

内存

在内存方面,ws的增长最为平缓,而socket.io早早的攀升到了极限最后挂掉了 测试结果:ws < websocket-node < faye < socket.io

CPU

在CPU方面,ws同样保持稳定,占用比也非常低。 测试结果:ws < websocket-node < faye < socket.io

总结

按第一得分4,第二得3分,第三得2分,第四得1分计算各个库的得分情况

得分

ws

21

websocket-node

17

faye

11

socket.io

11

ws表现最好简单易用,连接数最大,内存和CPU控制的稳定。缺点是在到达最大连接数极限之后,会断开所有连接

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一章:Websocket研究
    • WebSocket的生命周期
      • WebSocket的握手协议
        • 握手请求
        • 与http对比
    • 第二章:Nodejs 的Websocket模块选型
      • 本地Windows环境 不同消息大小的耗时对比库对比
        • 生产linux环境 不同消息大小的耗时对比库对比
          • 生产linux环境 测试内存波动
            • 生产linux环境 测试CPU波动
              • 生产linux环境 测试最大连接数
                • 生产linux环境 测试最大连接数时的内存与CPU波动
                  • 内存
                  • CPU
              • 总结
              相关产品与服务
              云服务器
              云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档