天天看点

WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展

文章目录

  • 前言
  • 一、WebSocket是什么?
  • 二、WebSocket出现之前的实时技术
  • 三、WebSocket应用场景
  • 四、WebSocket协议栈
  • 五、WebSocket与HTTP的区别
  • 六、WebSocket握手过程
  • 七、WebSocket帧格式
  • 八、WebSocket分片传输
  • 九、WebSocket相关扩展

前言

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

一、WebSocket是什么?

  • WebSocket 协议在2008年诞生,2011年成为国际标准。主流浏览器都已经支持。
  • WebSocket 是一种全新的协议。它将 TCP 的 Socket(套接字)应用在了网页上,从而使通信双方建立起一个保持在活动状态连接通道,并且属于全双工通信。
  • WebSocket 协议借用 HTTP协议 的 101 switch protocol 来达到协议转换,从HTTP协议切换WebSocket通信协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话。

二、WebSocket出现之前的实时技术

  • 轮询:最早的一种实现实时 Web 应用的方案。客户端以一定的时间间隔向服务端发出请求,以频繁请求的方式来保持客户端和服务器端的通信。
  • 长轮询:长轮询也采用轮询的方式,不过采取的是阻塞模型,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
  • 其他方式:如xhr-streaming、隐藏iframe、ActiveX控件、SSE。

下图是长轮询的一个示意图:

WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展

轮询技术非真正实时技术。使用 Ajax 方式模拟实时效果,每次客户端和服务器端交互,都是一次 HTTP 的请求和应答过程,且每次的 HTTP 请求和应答都带有完整 HTTP 头信息,增加传输的数据量。需构建两个http连接。客户端和服务器端编程实现比较复杂,为模拟真实的实时效果,需构造两个 HTTP 连接来模拟客户端和服务器的双向通信,一个连接用来处理客户端到服务器端的数据传输,一个连接用来处理服务器端到客户端的数据传输,增加了编程实现的复杂度、服务器端的负载,制约了应用系统的扩展性。

三、WebSocket应用场景

BS架构下的即时通讯、游戏等应用需要客户端与服务端间的双向通信,而HTTP的请求/响应模型并不适合这种场景。会存在一定的问题:

  • 服务器端被迫提供两类接口,一类提供给客户端轮询新消息,一类提供给客户端推送消息给服务器端。
  • HTTP协议有较多的额外开销,每次发送消息都会有一个HTTP header信息,而且如果不用Keep-Alive每次还都要握手。
  • 客户端的脚本比如JS可能还需要跟踪整个过程,发送一个消息后,我可能需要跟踪这个消息的返回。

Websocket出现使得浏览器提供socket的支持成为可能,从而在浏览器和服务器之间建立一条基于tcp的双向连接通道,web开发人员可以很方便的利用websocket构建实时web应用。

WebSocket适用于以下场景:

  • 在线聊天场景:例如qq聊天、淘宝与客服聊天、在线客服等等。这种场景都是需要实时的接收服务器推送的内容。
  • 协同办公:例如腾讯在线文档,腾讯的在线文档是支持多人编辑的,在excel中,一旦有人修改就要立即同步给所有人。
  • 直播弹幕:例如虎牙、斗鱼等各大直播平台,在直播时都是有弹幕的,遇到一些精彩片段时,往往会有弹幕刷屏。在这种情况下使用WebSocket会有一个更好的用户体验。
  • 位置共享:例如微信里位置共享,这种场景需要用户实时的共享自己的位置给服务器,服务器收到位置信息后,要实时的推送给其它共享者的,实时性要求较高;百度地图导航系统,在自己位置到达某个地方之后,语音会立即播报前面道路情况,比如上高架、下地道、拐弯、直行、学校慢行等等。这种场景实时性特别高,汽车速度很快,延迟1秒钟,可能就错过了最佳提醒时机。
  • 其他通过定义WebSocket子协议的扩展支持:例如sip、mqtt、xmpp、stomp等。

四、WebSocket协议栈

WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展

WebSocket是基于TCP的应用层协议。需要特别注意的是:虽然WebSocket协议在建立连接时会使用HTTP协议,但这并意味着WebSocket协议是基于HTTP协议实现的。

五、WebSocket与HTTP的区别

WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展
  • 通信方式不同。WebSocket是双向通信模式,客户端与服务器之间只有在握手阶段是使用HTTP协议的“请求-响应”模式交互,而一旦连接建立之后的通信则使用双向模式交互,不论是客户端还是服务端都可以随时将数据发送给对方;而HTTP协议则至始至终都采用“请求-响应”模式进行通信。也正因为如此,HTTP协议的通信效率没有WebSocket高。
  • 协议格式不同。HTTP协议的一个数据包就是一条完整的消息;而WebSocket客户端与服务端通信的最小单位是帧,由1个或多个帧组成一条完整的消息。即:发送端将消息切割成多个帧,并发送给服务端;服务端接收消息帧,并将关联的帧重新组装成完整的消息。

六、WebSocket握手过程

  • 客户端到服务端
    WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展

    GET ws://localhost…… HTTP/1.1 :打开阶段握手,使用http1.1协议。

    Upgrade:websocket,表示请求为特殊http请求,请求的目的是要将客户端和服务端的通信协议从http升级为websocket。

    Sec-websocket-key:Base64 encode 的值,是浏览器随机生成的。客户端向服务端提供的握手信息。

  • 服务端到客户端
    WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展

    101状态码:表示切换协议。服务器根据客户端的请求切换到Websocket协议。

    Sec-websocket-accept: 将请求头中的Set-websocket-key添加字符串并做SHA-1加密后做Base64编码,告知客户端服务器能够发起websocket连接。

  • 客户端发起连接的约定

    如果请求为wss,则在TCP建立后,进行TLS连接建立。

    请求的方式必须为GET,HTTP版本至少为HTTP1.1。

    请求头中必须有Host。

    请求头中必须有Upgrade,取值必须为websocket。

    请求头中必须有Connection,取值必须为Upgrade。

    请求头中必须有Sec-WebSocket-Key,取值为16字节随机数的Base64编码。

    请求头中必须有Sec-WebSocket-Version,取值为13。

    请求头中可选Sec-WebSocket-Protocol,取值为客户端期望的一个或多个子协议(多个以逗号分割)。

    请求头中可选Sec-WebSocket-Extensitons,取值为子协议支持的扩展集(一般是压缩方式)。

    可以包含cookie、Authorization等HTTP规范内合法的请求头。

  • 客户端检查服务端的响应

    服务端返回状态码为101代表升级成功,否则判定连接失败。

    响应头中缺少Upgrade或取值不是websocket,判定连接失败。

    响应头中缺少Connection或取值不是Upgrade,判定连接失败。

    响应头中缺少Sec-WebSocket-Accept或取值非法(其值为请求头中的Set-websocket-key添加字符串并做SHA-1加密后做Base64编码),判定连接失败。

    响应头中有Sec-WebSocket-Extensions,但取值不是请求头中的子集,判定连接失败。

    响应头中有Sec-WebSocket-Protocol,但取值不是请求头中的子集,判定连接失败。

  • 服务端处理客户端连接

    服务端根据请求中的Sec-WebSocket-Protocol 字段,选择一个子协议返回,如果不返回,表示不同意请求的任何子协议。如果请求中未携带,也不返回。

    如果建立连接成功,返回状态码为101。

    响应头Connection设置为Upgrade。

    响应头Upgrade设置为websocket。

    Sec-WebSocket-Accpet根据请求头Set-websocket-key计算得到,计算方式为:Set-websocket-key的值添加字符串: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11并做SHA-1加密后得到16进制表示的字符串,将每两位当作一个字节进行分隔,得到字节数组,对字节数组做Base64编码。

七、WebSocket帧格式

WebSocket通信流程如下:

WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展

Websocket帧格式如下:

WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展
  • 第一部分
    WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展

    FIN:1位,用于描述消息是否结束,如果为1则该消息为消息尾部,如果为零则还有后续数据包。

    RSV1,RSV2,RSV3:各1位,用于扩展定义,如果没有扩展约定的情况则必须为0。

    OPCODE:4位,用于表示消息接收类型,如果接收到未知的opcode,接收端必须关闭连接。

    OPCODE说明:

    0x0表示附加数据帧,当前数据帧为分片的数据帧。

    0x1表示文本数据帧,采用UTF-8编码。

    0x2表示二进制数据帧。

    0x3-7暂时无定义,为以后的非控制帧保留。

    0x8表示连接关闭。

    0x9表示ping。

    0xA表示pong。

    0xB-F暂时无定义,为以后的控制帧保留。

  • 第二部分
    WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展

    MASK:1位,用于标识PayloadData是否经过掩码处理。服务端发送给客户端的数据帧不能使用掩码,客户端发送给服务端的数据帧必须使用掩码。如果一个帧的数据使用了掩码,那么在Maksing-key部分必须是一个32个bit位的掩码,用来给服务端解码数据。

    Payload len:数据的长度:默认位7个bit位。如果数据的长度小于125个字节(注意:是字节)则用默认的7个bit来标示数据的长度。如果数据的长度为126个字节,则用后面相邻的2个字节来保存一个16bit位的无符号整数作为数据的长度。如果数据的长度大于126个字节,则用后面相邻的8个字节来保存一个64bit位的无符号整数作为数据的长度。

    payload len本来是只能用7bit来表达的,也就是最多一个frame的payload只能有127个字节,为了表示更大的长度,给出的解决方案是添加扩展payload len字段。当payload实际长度超过126(包括),但在2^16-1长度内,则将payload len置为126,payload的实际长度由长为16bit的extended payload length来表达。当payload实际长度超过216(包括),但在264-1长度内,则将payload置为127,payload的实际长度由长为64bit的extended payload length来表达。

  • 第三部分
    WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展
    数据掩码:如果MASK设置位0,则该部分可以省略,如果MASK设置位1,则Masking-key是一个32位的掩码。用来解码客户端发送给服务端的数据帧。
  • 第四部分
    WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展
    数据:该部分,也是最后一部分,是帧真正要发送的数据,可以是任意长度。

八、WebSocket分片传输

WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展
  • 控制帧可能插在一个Message的多个分片之间,但一个Message的分片不能交替传输(除非有扩展特别定义)。
  • 控制帧不可分片。
  • 分片需要按照分送方提交顺序传递给接收方,但由于IP路由特性,实际并不能保证顺序到达。

控制帧包括:

Close:用于关闭连接,可以携带数据,表示关闭原因。

Ping:可以携带数据。

Pong:用于Keep-alive,返回最近一次Ping中的数据,可以只发送Pong帧,做单向心跳。

连接关闭时状态码说明:

WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展

九、WebSocket相关扩展

  1. Stomp

    STOMP是基于帧的协议,它的前身是TTMP协议(一个简单的基于文本的协议),专为消息中间件设计。是属于消息队列的一种协议, 和AMQP, JMS平级。它的简单性恰巧可以用于定义websocket的消息体格式. STOMP协议很多MQ都已支持, 比如RabbitMq, ActiveMq。生产者(发送消息)、消息代理、消费者(订阅然后收到消息)。

WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展

2. SockJs

SockJS是一个浏览器JavaScript库,它提供了一个类似于网络的对象。SockJS提供了一个连贯的、跨浏览器的Javascript API,它在浏览器和web服务器之间创建了一个低延迟、全双工、跨域通信通道。

SockJS的一大好处在于提供了浏览器兼容性。优先使用原生WebSocket,如果在不支持websocket的浏览器中,会自动降为轮询的方式。 除此之外,spring也对socketJS提供了支持。

3. Socket.io

Socket.io实际上是WebSocket的父集,Socket.io封装了WebSocket和轮询等方法,会根据情况选择方法来进行通讯。

Sockei.io最早由Node.js实现,Node.js提供了高效的服务端运行环境,但由于Browser对HTML5的支持不一,为了兼容所有浏览器,提供实时的用户体验,并为开发者提供客户端与服务端一致的编程体验,于是Socket.io诞生了。Java模仿Node.js实现了Java版的Netty-socket.io库。

Socket.io将WebSocket和Polling机制以及其它的实时通信方式封装成通用的接口,并在服务端实现了这些实时机制相应代码,包括:AJAX Long Polling、Adobe Flash Socket、AJAX multipart streaming、Forever Iframem、JSONP Polling。

继续阅读