文章目录
- 前言
- 一、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。
下图是长轮询的一个示意图:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiYTMfhHLlN3XnxCM38FdsYkRGZkRG9lcvx2bjxSNx8VZ6l2cs0TP35WVlVHc1MVZwxUatg2VhVGTjFWW1I0Q2UTQClGVF5UMR9Fd4VGdsATNfd3bkFGazxycykFaKdkYzZUbapXNXlleSdVY2pESa9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLjFDZ0MDM2kzN1UGNkNTOhVDZhRTO3UTY2I2M0cjM4AzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
轮询技术非真正实时技术。使用 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是基于TCP的应用层协议。需要特别注意的是:虽然WebSocket协议在建立连接时会使用HTTP协议,但这并意味着WebSocket协议是基于HTTP协议实现的。
五、WebSocket与HTTP的区别
- 通信方式不同。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协议栈五、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来表达。
- 第三部分 数据掩码:如果MASK设置位0,则该部分可以省略,如果MASK设置位1,则Masking-key是一个32位的掩码。用来解码客户端发送给服务端的数据帧。
WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展 - 第四部分 数据:该部分,也是最后一部分,是帧真正要发送的数据,可以是任意长度。
WebSocket协议介绍前言一、WebSocket是什么?二、WebSocket出现之前的实时技术三、WebSocket应用场景四、WebSocket协议栈五、WebSocket与HTTP的区别六、WebSocket握手过程七、WebSocket帧格式八、WebSocket分片传输九、WebSocket相关扩展
八、WebSocket分片传输
- 控制帧可能插在一个Message的多个分片之间,但一个Message的分片不能交替传输(除非有扩展特别定义)。
- 控制帧不可分片。
- 分片需要按照分送方提交顺序传递给接收方,但由于IP路由特性,实际并不能保证顺序到达。
控制帧包括:
Close:用于关闭连接,可以携带数据,表示关闭原因。
Ping:可以携带数据。
Pong:用于Keep-alive,返回最近一次Ping中的数据,可以只发送Pong帧,做单向心跳。
连接关闭时状态码说明:
九、WebSocket相关扩展
-
Stomp
STOMP是基于帧的协议,它的前身是TTMP协议(一个简单的基于文本的协议),专为消息中间件设计。是属于消息队列的一种协议, 和AMQP, JMS平级。它的简单性恰巧可以用于定义websocket的消息体格式. STOMP协议很多MQ都已支持, 比如RabbitMq, ActiveMq。生产者(发送消息)、消息代理、消费者(订阅然后收到消息)。
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。