文章目录
背景
在项目开发时,我们经常需要与服务器进行持续的通讯以保持双方信息的同步。通常这种持久通讯在不刷新页面的情况下进行,消耗一定的内存资源常驻后台,并且对于用户不可见。就聊天的功能来说,在 WebSocket 出现之前,我们有以下解决方案:
传统轮询(Traditional Polling)
主要通过 Ajax 轮询请求,每隔一秒或者一段时间请求一次服务器查看是否有未读消息。浏览器需要不断的向服务器发送请求,而 HTTP 请求可能包含比较长的头部信息,其中真正有效的数据只占了一小部分,而每次请求数据都要发送一段很长的信息,会浪费很多的带宽等资源。
长轮询(Long Polling)
每一个请求发送到服务器时,服务器将请求卡主,直到有消息时才返回。这种方案会造成服务器很多连接占用。如果tomcat设置的连接数较少,会有无法连接的情况。还要注意默认http请求超时时间。
长轮询简易代码示例:
@GetMapping("/pull")
public string pull(){
while(true){
String message = messageService.pull();
if(message !=null ){
return message;
}
}
return null;
}
通过死循环或者notify/wait都可以,总之就是卡住请求不响应,一直等待有消息才响应。
一、什么是WebSocket
WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。WebSocket 是一种全新的协议。它将 TCP 的
Socket(套接字)
应用在了web page上,从而使通信双方建立起一个保持在活动状态连接通道,并且属于全双工(双方同时进行双向通信)。WebSocket 协议是借用 HTTP协议 的
101 switch protocol
来达到协议转换的,从HTTP协议切换成WebSocket通信协议。它的最大特点就是,
服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话
。
二、WebSocket场景
2.1、社交场景
在线聊天场景,例如qq聊天、淘宝与客服聊天、在线客服等等。这种场景都是需要实时的接收服务器推送的内容。
2.2、协同办公 / 编辑
腾讯在线文档,腾讯的在线文档是支持多人编辑的。在excel中,一旦有人修改就要立即同步给所有人。
2.3、直播弹幕
虎牙、斗鱼等各大直播平台,在直播时都是有弹幕的,遇到一些精彩片段时,往往一堆堆的弹幕刷屏。在这种情况下使用WebSocket会有一个更好的用户体验。
2.4、位置共享
微信里是有位置共享的,这种场景是需要用户实时的共享自己的位置给服务器,服务器收到位置信息后,要实时的推送给其它共享者的。这种是实时性要求较高。
百度地图导航系统,在自己位置到达某个地方之后,语音会立即播报前面道路情况,比如上高架、下地道、拐弯、直行、学校慢行等等。这种场景实时性特别高。汽车速度很快,延迟1秒钟,可能就错过了最佳提醒时机。
三、判断是否使用WebSocket
- 服务器是否向客户端推送数据
- 服务端向客户端推送数据的频率很大
- 实时性要求高
这时我就想到一个比较纠结的场景:
web扫码登录
扫码登录,在手机端认证登录之后。web是循环拉取认证结果,还是服务器推送。这里其实实时性也是有的,因为用户扫码之后,就在等待登录跳转。在登录的压力不大的情况,即使循环拉取,也不会造成很大的影响。如果压力大的情况下,可以采用WebSocket。
四、WebSocket协议解析
为了建立一个WebSocket连接,浏览器需要向服务器发送一个HTTP请求,这个请求和普通的HTTP请求不同。请求头中需要附加
Upgrade: WebSocket
。这样表示这是一个申请协议升级的HTTP请求。
GET /spring-WebSocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080
服务器解析对应的请求头进行响应。
HTTP/1.1 101 Switching Protocols
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp
成功响应的状态码为
101
,同样也有Upgrade表示服务器同意协议升级。成功握手后,HTTP 升级请求底层的 TCP 套接字保持打开状态,客户端和服务器都可以继续发送和接收消息。
请求消息中
Sec-WebSocket-Key
是随机的,服务器会用这些数据构造出一个SHA-1的信息摘要,把
Sec-WebSocket-Key
加上一个魔幻字符串。使用SHA-1加密,然后进行BASE-64编码,结果做为
Sec-WebSocket-Accept
头的值,返回给客户端。
有兴趣的小伙伴可以在
在线WebSocket调试
,通过浏览器开发者工具进行抓包查看。
五、WebSocket与http的区别
WebSocket 和 HTTP 的异同点
-
相同点:
- 都是基于 TCP 的可靠性传输协议
- 都工作在应用层
-
不同点
- WebSocket 中,浏览器和服务器只需要完成一次握手,就能建立持久性的连接,并进行双向数据传输(WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,是不需要HTTP协议的);建立了WebSocket 之后服务器不必在浏览器发送 request 请求之后才能发送信息到浏览器,服务器可以主动向浏览器发送数据,而且信息当中不必再带有 head 的部分信息了。与http的长链接通信相比,这种方式,不仅能降低服务器的压力,而且信息当中也减少了部分多余的信息,节省了带宽。
- HTTP 是单向的,浏览器与服务器进行通信,必须由浏览器发起请求,然后服务器返回结果(http链接分为短链接,长链接,短链接是每次请求都要三次握手才能发送自己的信息。即每一个request对应一个response。长链接是在一定的期限内保持 TCP 连接不断开。)