内容简介:需求:“客户端扫二维码,将客户端参数信息展示在web端”问题焦点:实时的web应用,Client 跟 Server 之间,实时的双向通信。
一、背景:源于一个需求
需求:“客户端扫二维码,将客户端参数信息展示在web端”
问题焦点:实时的web应用,Client 跟 Server 之间,实时的双向通信。
二、传统解决方案?
轮询(Polling):又称定期轮询
Client 定期向 Server 发送请求,以此保持与 Server 端数据的同步。典型应用场景:
-
Ajax技术,局部刷新Web页面
缺点:
-
带宽和 CPU 资源:由于 Client 定期向 Server 发送请求,当 Server 端没有数据更新时,Client仍旧发送请求,这造成带宽的浪费以及Server端CPU的耗费
-
实时性:轮询间隔内,会有数据延迟
长轮询(Long Polling):对普通轮询的改进和提高
目标:节省带宽,降低无效的网络传输。
基本原理:
-
保持连接:HTTP 层,保持连接,Server 接收到 Client 的请求之后,如果没有数据更新,则连接保持一段时间;
-
直到有数据更新或者连接超时,这样可以减少无效的 Client 与 Server 之间的交互;
-
通过保持连接,减少 Request 和 Response 的数量,节省带宽;
缺陷:
-
节省带宽,效果有限:HTTP的数据包HEAD部分数据量很大(400+Byte),但真正有效的数据很少(10Byte),这样的数据包在网络中周期传输,浪费带宽。
-
数据更新频繁场景下,数据实时性:当Server端数据频繁更新时,Server端必须等待下一个请求到来,才能发送更新的数据,这中间的延迟最高为 1.5 x RTT(往返时间)
-
网路拥塞场景下,等待时间更久,因为需要重新建立连接;
本质原因:
-
连接保持:需要重新建立 HTTP 连接(HTTP 1.1 只能缓解,无法从原理上,彻底解决)
-
数据格式:仍然为应用层的数据格式, HTTP HEADER 数据占用比较大
事件流方式(SSE)
-
通过 SSE ,客户端可以自动获取数据更新,而不用重复发送HTTP请求。一旦连接建立,“事件”便会自动被推送到客户端。服务器端SSE通过 事件流(Event Stream) 的格式产生并推送事件。
-
可以实现服务器到客户端的单向数据通信。
-
SSE相较于轮询具有较好的实时性,使用方法也非常简便。
缺点:
-
大并发情况下,服务器可能会宕机。
-
SSE只支持服务器到客户端单向的事件推送,而且所有版本的IE(包括到目前为止的Microsoft Edge)都不支持SSE。如果需要强行支持IE和部分移动端浏览器,可以尝试 EventSource Polyfill(本质上仍然是轮询)
三、WebSocket是什么?
B/S的请求-响应模式
-
传统Web中,是由 Browser 主动向 Server 端发送请求,以此获得 Server 端数据;
-
如果要实现实时通信,实时获取 Server 端的数据,通常是 Client 端定期发送HTTP请求,Server端进行响应并返回数据;
-
HTTP协议:基于请求/响应模式的、单向的、无状态的、应用层协议;
HTTP协议为什么不允许Server主动向Client推送数据?
如果允许 Server 向 Client 主动推送数据,则 Client 很容易受到攻击;特别是广告商会将广告信息,强行推送给 Client,因此 HTTP 的单向特性是必要的。
WebSocket简介
WebSocket协议借用HTTP协议的101( switch protocol) 状态码来达到协议转换,切换为WebSocket协议,它本身是基于Tcp协议的。
特点:
-
Client 跟 Server 之间,双向通信技术,Client 和 Server,都可以主动发起通信
-
是一种网络通信协议
-
建立在传输层 TCP 协议之上
优点:
-
节省带宽;(HTTP 协议的 HEAD 比较大)
-
节省服务器CPU资源;(HTTP 协议的 Polling 方式,即使 Server 没有数据也要接收 Request)
下图展示了Polling和WebSocket两种模式下,Web应用的效率:
四、协议
首先,WebSocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。HTTP的生命周期通过Request来界定,也就是一个Request一个Response,那么在HTTP1.0中,这次HTTP请求就结束了。HTTP1.1进行了改进,可以使用keep-alive保持连接,但是仍旧是一个Request = 一个Response, Response显得非常的被动,不能主动发起。
握手
来自客户端的握手信息:
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Origin: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13复制代码
重点请求首部含义:
-
Connection: Upgrade:表示要升级协议
-
Upgrade: websocket:表示要升级到 websocket 协议。
-
Sec-WebSocket-Version: 13:表示 websocket 的版本。如果服务端不支持该版本,需要返回一个 Sec-WebSocket-Versionheader ,里面包含服务端支持的版本号。
-
Sec-WebSocket-Key:是一个Base64 encode的值,由浏览器随机生成,与后面服务端响应首部的 Sec-WebSocket-Accept 是配套的,用于服务端校验,提供基本的防护,比如恶意的连接。
-
Sec_WebSocket-Protocol:是一个用户定义的字符串,用来区分同 URL 下,不同的服务所需要的协议。
来自服务器的握手信息:
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-WebSocket-Protocol: chat复制代码
重点响应首部含义:
-
Sec-WebSocket-Accept 根据客户端请求首部的 Sec-WebSocket-Key 计算出来。
-
Connection和Upgrade依然是表示协议升级为websocket协议。
切分数据帧
WebSocket 客户端、服务端通信的最小单位是 帧(frame),由 1 个或多个帧组成一条完整的消息(message)。
-
发送端:将消息切割成多个帧,并发送给服务端;
-
接收端:接收消息帧,并将关联的帧重新组装成完整的消息;
数据传递
一旦 WebSocket 客户端、服务端建立连接后,后续的操作都是基于数据帧的传递。
WebSocket的每条消息可能被切分成多个数据帧。当 WebSocket 的接收方收到一个数据帧时,会根据FIN(是数据帧当中的一个标识,用于判断当前帧是否为当前消息的最后一帧)的值来判断,是否已经收到消息的最后一个数据帧。
当接收到消息的最后一帧,即可以对消息进行处理。
心跳检测
很多原因都会触发连接关闭,一般情况是都会触发连接的onClose事件,但是当断网情况下是不会触发的onclose,这时候就不知道连接是断掉的,此时可以采用心跳重连,客户端每隔一段时间向服务端发送ping数据,服务端一旦苏醒,将进行pong响应,此时即可重新连接。心跳重连不是轮询,轮询会不断建立连接(多个连接),而心跳还是当前这个连接,只是一直发探测消息而已。
关闭连接
一旦发送或接收到一个Close控制帧,websocket 关闭阶段握手启动。
关闭状态码表(关闭原因)
状态码 |
名称 |
描述 |
---|---|---|
0–999 |
保留段, 未使用. |
|
1000 |
CLOSE_NORMAL |
正常关闭; 无论为何目的而创建, 该链接都已成功完成任务. |
1001 |
CLOSE_GOING_AWAY |
终端离开, 可能因为服务端错误, 也可能因为浏览器正从打开连接的页面跳转离开. |
1002 |
CLOSE_PROTOCOL_ERROR |
由于协议错误而中断连接. |
1003 |
CLOSE_UNSUPPORTED |
由于接收到不允许的数据类型而断开连接 (如仅接收文本数据的终端接收到了二进制数据). |
1004 |
保留. 其意义可能会在未来定义. |
|
1005 |
CLOSE_NO_STATUS |
保留. 表示没有收到预期的状态码. |
1006 |
CLOSE_ABNORMAL |
保留. 用于期望收到状态码时连接非正常关闭 (也就是说, 没有发送关闭帧). |
1007 |
Unsupported Data |
由于收到了格式不符的数据而断开连接 (如文本消息中包含了非 UTF-8 数据). |
1008 |
Policy Violation |
由于收到不符合约定的数据而断开连接. 这是一个通用状态码, 用于不适合使用 1003 和 1009 状态码的场景. |
1009 |
CLOSE_TOO_LARGE |
由于收到过大的数据帧而断开连接. |
1010 |
Missing Extension |
客户端期望服务器商定一个或多个拓展, 但服务器没有处理, 因此客户端断开连接. |
1011 |
Internal Error |
客户端由于遇到没有预料的情况阻止其完成请求, 因此服务端断开连接. |
1012 |
Service Restart |
服务器由于重启而断开连接. |
1013 |
Try Again Later |
服务器由于临时原因断开连接, 如服务器过载因此断开一部分客户端连接. |
1014 |
由 WebSocket 标准保留以便未来使用. |
五、优势
-
相较于HTTP协议,WebSocket支持持久连接;
-
服务器与客户端之间交换的标头信息很小,大概只有2字节;
-
客户端与服务器都可以主动传送数据给对方,真正的全双工;
-
不用频率创建TCP请求及销毁请求,减少网络带宽资源的占用,同时也节省服务器资源;
六、总结
WebSocket在用于双向传输、推送消息方面能够做到灵活、简便、高效,但在普通的Request-Response过程中并没有太大用武之地,比起普通的HTTP请求来反倒麻烦了许多,甚至更为低效。比如某些场景只需要简单的Request-Response,如果换做WebSocket还需要增加一个请求标识RequestId,增加成本。每项技术都有自身的优缺点,在适合它的地方能发挥出最大长处,而看到它的几个优点就不分场合地全方位推广的话,可能会适得其反。
七、实践
1、流程图
2、Attention Point
-
spring websocket需要tomcat为7.x及以上版本;
-
websocket的功能支持需要nginx和本机都增加支持websocket协议的配置;
3、Details
-
web端页面初始化生成一个唯一标识,标识当前web端页面;
-
将唯一标识放在二维码的url地址中生成二维码;
-
app端扫一扫,请求二维码对应的服务,同时这个请求携带了web端页面的唯一标识和app的一些参数信息;
-
服务端收到请求,将参数进行处理返回给携带了唯一标识的web端页面;
-
web端组件展示服务端响应的信息;
4、前端插件推荐
作者使用的是SpringMVC+React的前后端分离框架,这里推荐几个React不错的插件方便使用:
二维码生成插件: github.com/zpao/qrcode…
八、参考
附: 轮询、长轮询、短连接、长连接区别对比
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Apache Pig简介与实践
- Apache Pig简介与实践
- Apache Pig简介与实践
- Spring Boot Admin 简介及实践
- Spring Boot Admin简介及实践
- [译]WebRTC基础实践 - 1. WebRTC简介
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。