WebSocket简介与最佳实践

栏目: Html5 · 发布时间: 6年前

内容简介:需求:“客户端扫二维码,将客户端参数信息展示在web端”问题焦点:实时的web应用,Client 跟 Server 之间,实时的双向通信。

一、背景:源于一个需求

需求:“客户端扫二维码,将客户端参数信息展示在web端”

问题焦点:实时的web应用,Client 跟 Server 之间,实时的双向通信。

WebSocket简介与最佳实践

二、传统解决方案?

轮询(Polling):又称定期轮询

Client 定期向 Server 发送请求,以此保持与 Server 端数据的同步。典型应用场景:

  • Ajax技术,局部刷新Web页面

缺点:

  • 带宽和 CPU 资源:由于 Client 定期向 Server 发送请求,当 Server 端没有数据更新时,Client仍旧发送请求,这造成带宽的浪费以及Server端CPU的耗费

  • 实时性:轮询间隔内,会有数据延迟

WebSocket简介与最佳实践

长轮询(Long Polling):对普通轮询的改进和提高

目标:节省带宽,降低无效的网络传输。

基本原理:

  • 保持连接:HTTP 层,保持连接,Server 接收到 Client 的请求之后,如果没有数据更新,则连接保持一段时间;

  • 直到有数据更新或者连接超时,这样可以减少无效的 Client 与 Server 之间的交互;

  • 通过保持连接,减少 Request 和 Response 的数量,节省带宽;

缺陷:

  • 节省带宽,效果有限:HTTP的数据包HEAD部分数据量很大(400+Byte),但真正有效的数据很少(10Byte),这样的数据包在网络中周期传输,浪费带宽。

  • 数据更新频繁场景下,数据实时性:当Server端数据频繁更新时,Server端必须等待下一个请求到来,才能发送更新的数据,这中间的延迟最高为 1.5 x RTT(往返时间)

  • 网路拥塞场景下,等待时间更久,因为需要重新建立连接;

WebSocket简介与最佳实践

本质原因:

  • 连接保持:需要重新建立 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简介与最佳实践

四、协议

首先,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、流程图

WebSocket简介与最佳实践

2、Attention Point

  • spring websocket需要tomcat为7.x及以上版本;

  • websocket的功能支持需要nginx和本机都增加支持websocket协议的配置;

3、Details

  1. web端页面初始化生成一个唯一标识,标识当前web端页面;

  2. 将唯一标识放在二维码的url地址中生成二维码;

  3. app端扫一扫,请求二维码对应的服务,同时这个请求携带了web端页面的唯一标识和app的一些参数信息;

  4. 服务端收到请求,将参数进行处理返回给携带了唯一标识的web端页面;

  5. web端组件展示服务端响应的信息;

4、前端插件推荐

作者使用的是SpringMVC+React的前后端分离框架,这里推荐几个React不错的插件方便使用:

二维码生成插件: github.com/zpao/qrcode…

八、参考

ningg.top/websocket-i…

segmentfault.com/a/119000001…

segmentfault.com/a/119000001…

附: 轮询、长轮询、短连接、长连接区别对比


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Agile Web Development with Rails, Third Edition

Agile Web Development with Rails, Third Edition

Sam Ruby、Dave Thomas、David Heinemeier Hansson / Pragmatic Bookshelf / 2009-03-17 / USD 43.95

Rails just keeps on changing. Rails 2, released in 2008, brings hundreds of improvements, including new support for RESTful applications, new generator options, and so on. And, as importantly, we’ve a......一起来看看 《Agile Web Development with Rails, Third Edition》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具