来自Wi-Fi专家的声音

 

WebSocket的话题


上次介绍了基于代理的推送型消息传输协议 MQTT。在网上搜索 MQTT 常会看到与 MQTT 搭配使用的技术要素WebSocket” 这一关键词。本次将简单一下 WebSocket

什么是WebSocket

WebSocket 是一种基于 HTTP 的叠加协议,可在已建立的 HTTP/HTTPS 接上实现任意度、任意格式数据的双向通信。它已作RFC6445 IETF 完成标准化。
之前在 “HTTP 的话题 中介绍过 “HTTP/2 是在基于 TCP 运行的 HTTP 之上,实现了类似 TCP 功能的协议”,从定位上来WebSocket 也与之非常相似。不过WebSocket 的实现 HTTP/2 更为简单。例如,HTTP/2 能在单 HTTP 会话理多条虚拟连接,而 WebSocket 的虚拟连接与 HTTP 会话 1:1 的对应关系。两者以相同的方法论解决同一问题,却因切入角度不同形成了看似相似却又不同的准(而且提出者都是谷歌!),不过这算机域却是常象。

WebSocket 是专为 JavaScript 首的脚本言使用而开的。在 JavaScript API 中提供了 WebSocket 象,通过对该对 opensendmessageclose 等读写操作,开者能够像在原始 TCP 接上通信一样进程。
需要注意的是,“看起来像原始 TCP” 指的是源代码层面的表WebSocket 底是运行在 HTTP/HTTPS 之上的叠加协议并非向 JavaScript 提供 socket API 的技术设计上的一大顾虑是,若将 WebSocket 用作 socket 的替代品,可能会被用于端口扫描、代理装等黑客攻防范一点,WebSocket 引入了一些看似奇特的规格(※注)。

※注:诸如「Sec-WebSocket-Key」及「负载」等概念,本文将不深入探细节
 

什么需要这样西呢

正如 “HTTP 的话题 中介绍的那HTTP 最初是为实现文档共享而开的。其基本工作原理采用求(客 / 浏览器)→响(服器)的往返模式。在 HTTP/1.0 及之后版本中,可通过 POST 命令实现端向服器方向的数据传输HTTP/1.1 及之后版本支持使用 Chunked Encoding,允许在数据度不确定的情况下启通信。但无哪个版本,服器向客端的通信始只能作为对请求的响送,且必等待求完成后才能返回响
也就是说HTTP无法在任意时间向客端方向传输任意数据。因此,在AJAX中,曾经使用一种称为轮询实现方式,即每隔10秒等固定时间间隔向服送碎片化的求以取响,但种方式不可避免地存在响应时间的上限。而且,如果短响应时间轮询间隔,通信效率又会降低,两者相互矛盾。

我好像记得很久以前的电话连TSS系统也做类似的事情,不禁人思考人类到底在做什么。随着“互网”的使用方式从“网页浏览展到消息传递、聊天等双向实时交互,HTTP的局限性愈发了快速(※注)解决问题,开WebSocket;而为了更深入地解决问题,开HTTP/2,这就是它的定位。

※注:原本应该是一种“快速解决法”的WebSocket,却在RFC草案阶段被反复批,其范多次更。由于基于多次修中的草案版本的实现经发布到市上,因此要涵盖包括渡草案版本在内的所有范,得非常困

什么不能用普通的Socket套接字呢?

一点在 HTTP 的话题 中也提到过,我认为最主要的原因在于,如今的 “互联网” 是基于 “只要能浏览就行”一前提展普及的,因此形成了充斥着代理服器(Proxy)、网络地址转换NAT)、防火墙Firewall)等重重壁垒状。要打破已形成的壁全世界的互设备级为 IPv6 兼容!),或是在壁垒上开新的通用接口(全世界的互设备开放 HTTP 以外的新端口),我认为都不现实。但既然存在 “能够穿透 NAT 和代理服务器”“也支持安全防 HTTP 协议,那么利用它实现协同效才是现实选择
1995 年制定的 IPv6 准中,包含了旨在实现 “此类应用” 的诸设计,例如支持一多通信的 Multicast 、无需依赖连接状即可追踪数据包的 Flow Labe 、强制要求实现安全功能的 IPsecAH/ESP) 等。然而现实中,人却跳设计选择了一种从技角度堪称 “畸形” 的方案 ——“在 HTTP/TLS 之上搭载类似 TCP 的协议”。果然也是 “常见现象”(※注)。

※注:所谓 “常见现象” 的典型程度,例:为了在连续最多 76 个英数字符的串行线路上传输邮件而开UUCP,被直接作为SMTP移植到互联网上;了在 SMTP 上处理任意二制数据,开了将数据转换为 76 字符宽度英数字符的BASE64 编码;出于安全考实现SMTP over TLS;结 “将 HTML 转换为 76 字符宽度英数字符的 BASE64 编码,加密后通 TCP 传输种无意的操作成日常。

WebSocket 的工作原理

关于 WebSocket,已经可以通语获取丰富的信息,因此本博客不会深入探其工作序列或格式细节仅阐述最基本的工作原理。
WebSocket 的初始化由客户端的求与服器的响往返开始,段的通信格式本身就是 HTTP。与 “纯粹的” HTTP 不同的是,此时会附加 Connection: Upgrade 标头(※注)。通过该标头,即便在求~响完成后,TCP/TLS 接仍会保持;不,此接上传输的不再是 HTTP,而是 WebSocket 协议明确一点,会附加 Upgrade: WebSocket 标头)—— 双方通过这种方式达成共

※注:在普通的 HTTP 协议中,字段要么是Connection: Close,要么是Connection: Keep-Alive

图示

描述已自动生成{C}

WebSocket 的会话建立

初始化完成后,数据仅需在接上双向传输即可。但与普通的 TCP 套接字不同,此时传输的并非 “单纯的字流(Byte Stream)”,而是会附加简单标头以指示数据度。一点与 TLS 中的消息 / 记录结构略有相似。当 WebSocket TLS 上运行时WebSocket 标头会被 TLS 记录包裹,再附加 TCP 标头后以 IP 数据包的形式传输。虽然会人感觉这是某种多此一绕远路的操作,但考 WebSocket 本就是在层层叠叠的技上开出来的,也是无可奈何的事。

表格

描述已自动生成{C}

WebSocket 的标头

WebSocket的标头负载长度采用了一种稍特殊的编码方式。如果负载长度在0125字节,就用1个字节来表示;如果“负载长度”字段的126,那么就会附加一个16位的扩度字段;如果是127,则会附加一个32位的扩度字段。规则与日前提到的 MQTT 消息长规则似是而非,但两者都与臭名昭著的 OSI ASN.1 BER 规则中的可变长编码有几分相似。

图片包含 表格

描述已自动生成{C}

WebSocket的长编码规则
如果第一个字节
小于125,那么这就是负载长度本身。
如果第一个字节值为126,则会附加一个16位的长度字段;
如果第一个字节值为127,则会附加一个32位的长度字段。
字节顺 Big-Endian

文本, 表格

描述已自动生成{C}

MQTT 的消息长编码规则
消息长
度是按每7位存储的,bit7 用于指示后续是否有字段。
字节顺 Little-Endian

表格

描述已自动生成{C}

ASN.1的长编码规则
如果第一个字节
bit70,那么bit0bit6表示的就是长度本身;
如果第一个字节bit71,那么bit0bit6表示后续长度字段的度。
字节顺 Big-Endian

OSI 中大量使用的可变长标头设计,在 IETF 中评价极差,被批判为 “片面追求传输效率”、“忽视实现效率”、“电话工程咒” 等。尽管 IPv6 采用了近乎偏执贯彻 64 位边界的固定长标头设计(※注),但 20 年后人们却再次 “果然还是可变长编码更高效”——不禁 “人类究竟在做什么” 的困惑,但这 “常见现象”。方法中本就没有绝对的好坏,其价取决于与使用境的适配性,而境始在不断化。

不过,存在三种似是而非的编码方式,真想一句 “差不多得了”。

※注:所谓 “偏执 到什么程度呢?以存储 MAC 地址的源 / 目标链地址选项字段例:字段由1 字节类型(1 2)、1 字节标头长度后接 MAC 地址构成。当 MAC 地址为 48bit6 字节标头总长度恰好 64bit8 字节),完全对齐 64 位边界。但设计凑而缺乏 MAC 地址类型 / 度的字段。例如,若要传输 IEEE802.15.4 中使用的 64bitEUI-64)地址,会超出 2 字节,需按 64bit 位向上取整,标头长变为 16 字节2×64bit)。更麻烦的是,地址度和填充度未在任何字段中标识,只能通过协议框架外的信息(如层驱动描述符)查询地址 —— 这实在称不上 “优雅” 的设计。我认为这是一种因度追求 64 位边 “整齐性” 而显得勉强的格。

总结

WebSocket 是迫于需求而开发的技,但正如多次提到的,它是 “层层叠叠堆叠起来的物”、“技上堪称畸形”。而这样的技之所以被需要,我认为恰恰如反映了 IPv6 的现状。起来,上次提到的 MQTT 也是如此 —— 在 IETF 构想的 “理想中的下一代互联网” 中,本应多播技术实现的功能,如今却要向 1000 个会话订阅者重复 1000 次相同消息,这 “无意义的操作” 本应是可以避免的。
我并非想说 IPv6 是失败的或毫无意的。大地址空需,它早会逐步取代 IPv4。然而,诸如多播、任意播、流标签IPsec 等作为 “下一代互联准制定”一宏大工程核心的技,本是 IETF 年轻工程师们寄予未来的 “播种”,最终却未能芽。
不过 10 年、20 年后会变成什么样还不得而知。或:“居然在用代理服器分数据?使用多播不是常识吗!” 或者 “竟然还有系在使用 TLS?使用 IPsec 不是常识吗!”。竟技的最佳解决方案会随着境的化而不断改

相关连接