WebSocket-之协议基础

11次阅读

共计 1772 个字符,预计需要花费 5 分钟才能阅读完成。

引言

随着 Web 领域的飞速发展,最初设计得十分简单的 HTTP 协议在当今的应用上显得捉襟见肘,协议的瓶颈也逐渐显露出来。

“既然 HTTP 这么烂?为什么我们不抛弃它再设计一个全新的协议,而是要给他打补丁呢?”这是某次我和我舍友在宿舍喝着小酒,探讨 SpringMVC 时谈到的一个话题。

最初的 HTTP,只是想把HTTP 当作传输 HTML 文档的协议,设计者没有想到 HTTP 经久不衰,需要承受越来越复杂的业务职责。

所以 HTTP 的设计无可厚非,只是它不“那么地”适应这个时代了。但是目前基于 HTTP 协议实现的 Web 浏览器遍布全球,并不能随意动摇 HTTP 的地位。

所以为了满足现代社会日益增长的业务需求,涌现出无数企图“消除”HTTP瓶颈的解决方案,其中的一项就是——“WebSocket”。

栗子

为什么会出现 WebSocket 协议呢?

假设我们去实现类似微信一样的网页在线聊天工具,我们要解决什么问题呢?

很显然,消息推送是当前业务场景下的一个技术瓶颈。

当前账号收到了消息,我们怎么在网页里“实时地”获取到消息并显示呢?注意要保障在线聊天的实时性。

方案一:只使用 HTTP

能实现吗?显然不能。

浏览器向客户端发起 HTTP 请求,请求到含有当前消息的 HTML 文件,渲染给用户。请求结束,不考虑持久连接的情况下,断开 TCP 连接。

当服务器有新消息时,除非用户当前网页刷新,否则在只使用 HTTP 的情况下无法实现实时性。

方案二:再加上 Ajax

Ajax意思就是用 JavaScript 执行异步网络请求。
——《廖雪峰的 JavaScript 教程》

使用Ajax,可以在浏览器内用JavaScript“偷偷”地发起网络请求,查询最新的消息,降低操作成本,提升用户体验。

为了保证实时性,需要前台定时发送 Ajax 请求。例如:每 5s 发送一次网络请求查询消息,将数据的延时性保持在固定间隔以内。

缺点很明显,会产生大量的 HTTP 请求,如果消息长时间没有更新,十分浪费通信资源。

方案三:再加上 Comet

为了避免产生大量无用的 HTTP 请求,产生了Comet

Ajax发起查询消息的请求,服务器接收到该消息,不会立即响应,Comet会将响应置于挂起状态,当服务器端有内容更新时,再返回响应。

与方案二相比,减少了无用的 HTTP 请求,同时也保证了数据的实时性。

缺点就是服务器压力过大,服务器为了保持挂起的 HTTP 响应,会消耗更多的宝贵的服务器资源。

方案四:WebSocket

因为 HTTP 是请求响应模式,所以如果是基于 HTTP 实现实时性,过于复杂。请求都是客户端发起的,客户端怎么知道服务器的内容什么时候更新呢?

所以,2011 年 12 月 11 日 RFC 6455 - The WebSocket Protocol 标准被确立。

WebSocket,同样基于 TCP 协议,是 Web 浏览器与 Web 服务器之间的全双工通信标准。

如果有数据更新,服务器可以向客户端发送数据,使实现实时性变得简单。

协议详解

WebSocket连接的建立需要握手,说是握手,其实也是为了兼容 HTTP 浏览器的一种手段。

握手之请求

客户端向服务器发送 HTTP 数据包,请求建立握手。

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xxxxxxxxxx
Sec-WebSocket-Version: 13

具体的细节我就不描述了,自己去查阅文档。

客户端发送 HTTP 请求,首部 Upgrade: websocket,表示客户端希望将通信协议从HTTP 升级为 WebSocket 协议。

握手之响应

服务器返回响应,同意切换协议。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: xxxxxxxxxx

HTTP响应状态码101,切换协议。

通信

握手之后即建立起了连接,开始全双工通信。

WebSocketHTTP 协议类似,其资源地址类似:ws://server.example.com:8080/path

总结

本文共同讨论了 WebSocket 协议的一些理论基础,夜深了,先写到这里。

下一篇文章,使用 spring-boot 实现简易的 WebSocket 示例。

正文完
 0