WebSocket协议

2022/1/20

# Http协议的弊端

将HTTP协议的主要弊端总结如下:

  1. HTTP协议为半双工协议。半双工协议指数据可以在客户端和服务端两个方向上传输,但是不能同时传输。它意味着在同一时刻,只有一个方向上的数据传送;
  2. HTTP 消息冗长而繁琐。HTTP 消息包含消息头、消息体、换行符等,通常情况下采用文本方式传输,相比于其他的二进制通信协议,冗长而繁琐;
  3. 针对服务器推送的黑客攻击。例如长时间轮询。

现在,很多网站为了实现消息推送,所用的技术都是轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出 HTTP request,然后由服务器返回最新的数据给客户端浏览器。这种传统的模式具有很明显的缺点,即浏览器需要不断地向服务器发出请求,然而HTTP request 的Header是非常冗长的,里面包含的可用数据比例可能非常低,这会占用很多的带宽和服务器资源。

比较新的一种轮询技术是Comet,使用了AJAX。这种技术虽然可达到双向通信,但依然需要发出请求,而且在 Comet中,普遍采用了长连接,这也会大量消耗服务器带宽和资源。

为了解决HTTP协议效率低下的问题,HTML5定义了WebSocket协议,能更好地节省服务器资源和带宽并达到实时通信。

# WebSocket 简介

WebSocket 是 HTML5 开始提供的一种浏览器与服务器间进行全双工通信的网络技术。

在 WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道,两者就可以直接互相传送数据了。WebSocket基于TCP双向全双工进行消息传递,在同一时刻,既可以发送消息,也可以接收消息,相比HTTP的半双工协议,性能得到很大提升。

# WebSocket 特点

  • 单一的TCP连接,采用全双工模式通信;
  • 对代理、防火墙和路由器透明;
  • 无头部信息、Cookie和身份验证;
  • 无安全开销;
  • 通过“ping/pong”帧保持链路激活;
  • 服务器可以主动传递消息给客户端,不再需要客户端轮询

# WebSocket 连接过程

# 建立连接

建立WebSocket连接时,需要通过客户端或者浏览器发出握手请求。

image-20220110112613428

为了建立一个 WebSocket连接,客户端浏览器首先要向服务器发起一个HTTP请求,这个请求和通常的HTTP请求不同,包含了一些附加头信息,其中附加头信息“Upgrade:WebSocket”表明这是一个申请协议升级的HTTP请求。

服务器端解析这些附加的头信息,然后生成应答信息返回给客户端,客户端和服务器端的 WebSocket连接就建立起来了,双方可以通过这个连接通道自由地传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动关闭连接。

服务端返回给客户端的应答消息:

image-20220110112806457

请求消息中的“Sec-WebSocket-Key”是随机的,服务器端会用这些数据来构造出一个SHA-1的信息摘要,把“Sec-WebSocket-Key”加上一个魔幻字符串“258EAFA5-E914-47DA-95CA-C5ABODC85B11”。使用SHA-1加密,然后进行BASE-64编码,将结果做为“Sec-WebSocket-Accept”头的值,返回给客户端。

# WebSocket 连接的生命周期

握手成功之后,服务端和客户端就可以通过“messages”的方式进行通信了,一个消息由一个或者多个帧组成,WebSocket的消息并不一定对应一个特定网络层的帧,它可以被分割成多个帧或者被合并。

帧都有自己对应的类型,属于同一个消息的多个帧具有相同类型的数据。从广义上讲,数据类型可以是文本数据(UTF-8[RFC3629]文字)、二进制数据和控制帧(协议级信令,如信号)。

WebSocket连接生命周期示意图如图所示:

image-20220110112943964

# 关闭连接

为关闭WebSocket连接,客户端和服务端需要通过一个安全的方法关闭底层TCP连接以及TLS会话。如果合适,丢弃任何可能已经接收的字节,必要时(比如受到攻击)可以通过任何可用的手段关闭连接。

底层的 TCP连接,在正常情况下,应该首先由服务器关闭。在异常情况下(例如在一个合理的时间周期后没有接收到服务器的TCP Close),客户端可以发起TCP Close。因此,当服务器被指示关闭WebSocket连接时,它应该立即发起一个TCP Close操作;客户端应该等待服务器的 TCP Close。

WebSocket的握手关闭消息带有一个状态码和一个可选的关闭原因,它必须按照协议要求发送一个Close控制帧,当对端接收到关闭控制帧指令时,需要主动关闭WebSocket连接。

# MQTT与WebSocket的对比

# 相同点

  • MQTT 和 WebSocket 都是应用层协议
  • 目前底层都是使用 TCP 协议确保可靠传输数据
  • 都规定了自己的报文(消息)结构
  • 都支持双向通信
  • 都使用二进制编码(有别于 HTTP 这一类基于文本编码的协议)
  • 都是公开标准 mqttrfc6455

# 不同点

1、通信模型不同

MQTT 是一套比较复杂的消息投递协议,而 WebSocket则只是在TCP协议之上实现了简单的报文通信。

2、报文结构不同

3、会话协商方式不同

WebSocket 基于 HTTP/1.1 的 Upgrade 机制协商会话。一旦完成协商,就会获得一个双工信道,可以双向传递数据。

MQTT 协议则需要通过 CONNECT 报文协商会话。TCP连接建立之后,客户端会主动发送 CONNECT 报文。服务端准备好之后会回应 CONNACK 报文。

4、消息收发方式不同

WebSocket 收发消息不需要对方确认。因为底层的 TCP 协议会完成可靠传输

MQTT 收发消息需要根据投递级别进行确认

5、保活机制不同

WebSocket 只规定了 ping/pong 两种报文,但并不强制要求定时收发心跳包。

MQTT 则有明确的心跳协商机制。协商会话使用的 CONNECT 报文包含 Keep Alive 头部信息,结构如下:

imgimg

使用两个字节传输心跳间隔,单位是秒。会话协商后需要定时收发 PINGREQ 和 PINGRESP 报文。

6、使用场景不同

MQTT 主要应用在物联网等场景,WebSocket 因为有配套的浏览器API,主要应用在 Web 开发领域。但两者均为通用的应用层协议,可以在任何相关的场景使用。

# MQTT

MQTT协议是为大量计算能力有限,且工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议,它具有以下主要的几项特性:

  1. 使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合;
  2. 对负载内容屏蔽的消息传输;
  3. 使用 TCP/IP 提供网络连接;
  4. 有三种消息发布服务质量:
    1. “至多一次”,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
    2. “至少一次”,确保消息到达,但消息重复可能会发生。
    3. “只有一次”,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。

# 为什么不使用MQTT?

许多的边缘设备采纳MQTT作为消息总线.而且云端应用中也使用基于pub/sub 的消息系统.毕竟采纳现成的系统会可靠一点。

MQTT 对于短小,低速的IOT 消息交换是可行的,但是如果是高速的大数据流,MQTT 的传输速度不快。

# WebSocket协议

  • WebSocket协议是基于TCP的一种应用层网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
  • 取代了网页和服务器采用HTTP轮询进行双向通讯的机制。

# 参看