websocket和tcp区别,websocket服务器要多大

首页 > 技术 > 作者:YD1662022-10-26 13:04:40

各个字段的解释如下:

更多细节请参考RFC6455-数据帧,这里不作赘述。

针对上面的各个字段的介绍,有一个Mask的需要说一下。

掩码键(Masking-key)是由客户端挑选出来的32位的随机数。掩码操作不会影响数据载荷的长度。

掩码、反掩码操作都采用如下算法。

首先,假设:

算法描述为: original-octet-i 与 masking-key-octet-j 异或后,得到 transformed-octet-i。

即: j = i MOD 4 transformed-octet-i = original-octet-i XOR masking-key-octet-j

用代码实现:

const mask = (source, mask, output, offset, length) => {

for(vari = 0; i < length; i ) {

output[offset i] = source[i ] ^ mask[i & 3];

}

};

解掩码是反过来的操作:

const unmask = (buffer, mask) => {

// Required until [url=https://github.com/nodejs/node/issues/9006]https://github.com/nodejs/node/issues/9006[/url] is resolved.

const length = buffer.length;

for(vari = 0; i < length; i ) {

buffer[i ] ^= mask[i & 3];

}

};

同样的为什么需要掩码操作,也可以参考之前的那篇文章:《理论联系实际:从零理解WebSocket的通信原理、协议格式、安全性》,完整的我就不列举了。

需要注意的重点,我引用一下:

WebSocket协议中,数据掩码的作用是增强协议的安全性。但数据掩码并不是为了保护数据本身,因为算法本身是公开的,运算也不复杂。除了加密通道本身,似乎没有太多有效的保护通信安全的办法。

那么为什么还要引入掩码计算呢,除了增加计算机器的运算量外似乎并没有太多的收益(这也是不少同学疑惑的点)。

答案还是两个字: 安全。但并不是为了防止数据泄密,而是为了防止早期版本的协议中存在的代理缓存污染攻击(proxy cache poisoning attacks)等问题。

5、Socket.io5.1 本节引言

websocket和tcp区别,websocket服务器要多大(5)

介绍完上一节WebSocket协议,我们把视线转移到现代Web端即时通讯技术的第二个利器:socket.io。

估计有读者就会问,WebSocket和socket.io有啥区别啊?

在了解socket.io之前,我们先聊聊传统Web端即时通讯“长连接”技术的实现背景。

5.2 传统Web长连接的技术实现背景

在现实的Web端产品中,并不是所有的Web客户端都支持长连接的,或者换句话说,在WebSocket协议出来之前,是三种方式去实现WebSocket类似的功能的。

这三种方式是:

那么如果单纯地使用WebSocket的话,那些不支持的客户端怎么办呢?难道直接放弃掉?

当然不是。Guillermo Rauch大神写了socket.io这个库,对WebSocket进行封装,从而让长连接满足所有的场景,不过当然得配合使用对应的客户端代码。

socket.io将会使用特性检测的方式来决定以websocket/ajax长轮询/flash等方式建立连接。

那么socket.io是如何做到这些的呢?

我们带着以下几个问题去学习:

如果有童鞋对上述问题已经清楚,想必就没有往下读的必要了。

5.3 socket.io的介绍

通过前面章节,读者们都知道了WebSocket的功能,那么socket.io相对于WebSocket,在此基础上封装了一些什么新东西呢?

socket.io其实是有一套封装了websocket的协议,叫做engine.io协议,在此协议上实现了一套底层双向通信的引擎Engine.io。

而socket.io则是建立在engine.io上的一个应用层框架而已。所以我们研究的重点便是engine.io协议。

在socket.io的README中提到了其实现的一些新特性(回答了问题一):

注意:Socket.IO不是WebSocket的实现,虽然 Socket.IO确实在可能的情况下会去使用WebSocket作为一个transport,但是它添加了很多元数据到每一个报文中:报文的类型以及namespace和ack Id。这也是为什么标准WebSocket客户端不能够成功连接上 Socket.IO 服务器,同样一个 Socket.IO 客户端也连接不上标准WebSocket服务器的原因。

5.4 engine.io协议介绍

完整的engine.io协议的握手过程如下图:

websocket和tcp区别,websocket服务器要多大(6)

当前engine.io协议的版本是3,我们根据上图来大致介绍一下engine.io协议。

5.4.1)engine.io协议请求字段:

我们看到的是请求的url和WebSocket不大一样,解释一下:

除了上述的3个字段,协议还描述了下面几个字段:

另外engine.io默认的path是 /engine.io,socket.io在初始化的时候设置为了 /socket.io,所以大家看到的path就都是 /socket.io 了:

function Server(srv, opts){

if(!(this instanceof Server)) return new Server(srv, opts);

if('object'== typeof srv && srv instanceof Object && !srv.listen) {

opts = srv;

srv = null;

}

opts = opts || {};

this.nsps = {};

this.parentNsps = new Map();

this.path(opts.path || '/socket.io');

5.4.2)数据包编码要求:

engine.io协议的数据包编码有自己的一套格式,在协议介绍上engine.io-protocol,定义了两种编码类型: packet和payload。

一个编码过的packet是下面这种格式:

<packettype id>[<data>]

然后协议定义了下面几种packet type(采用数字进行标识):

那payload也有对应的格式要求:

注意:payload的编码要求不适用于WebSocket的通信。

针对上面的编码要求,我们随便举个例子.

之前在第一条polling请求的时候,服务端编码发送了这个数据:

97:0{"sid":"Peed250dk55pprwgAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000}2:40

根据上面的知识,我们知道第一次服务端会发送一个open的数据包。

所以组装出来的packet是:

0

然后服务端会告知客户端去尝试升级到websocket,并且告知对应的sid。

于是整合后便是:

0{"sid":"Peed250dk55pprwgAAAA","upgrades":"websocket","pingInterval":25000,"pingTimeout":60000}

接着根据payload的编码格式,因为是string,且长度是97个字节。

所以是:

97:0{"sid":"Peed250dk55pprwgAAAA","upgrades":"websocket","pingInterval":25000,"pingTimeout":60000}

接着第二部分数据是message包类型,并且数据是0,所以是40,长度为2字节,所以是2:40,最后就拼成刚才大家看到的结果。

注意:

ping/pong的间隔时间是服务端告知客户端的:"pingInterval":25000,"pingTimeout":60000,也就是说心跳时间默认是25秒,并且等待pong响应的时间默认是60s。

5.5 升级协议的必备过程

协议定义了transport升级到websocket需要经历一个必须的过程。

如下图:

websocket和tcp区别,websocket服务器要多大(7)

WebSocket的测试开始于发送probe,如果服务器也响应probe的话,客户端就必须发送一个upgrade包。

为了确保不会丢包,只有在当前transport的所有buffer被刷新并且transport被认为paused的时候才可以发送upgrade包。服务端收到upgrade包的时候,服务端必须假设这是一个新的通道并发送所有已存的缓存到这个通道上

在Chrome上的效果如下:

websocket和tcp区别,websocket服务器要多大(8)

上一页12345下一页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.