「Web应用架构」WebSocket 协议介绍

简介: 「Web应用架构」WebSocket 协议介绍

由HyBi工作组开发的WebSocket有线协议(RFC 6455)由两个高级组件组成:用于协商连接参数的开放HTTP握手和二进制消息帧机制,以实现低开销、基于消息的文本和二进制数据传输。

WebSocket协议试图在现有HTTP基础架构的上下文中解决现有双向HTTP技术的目标;因此,它被设计为在HTTP端口80和443上工作……然而,这种设计并没有将WebSocket限制为HTTP,而且未来的实现可以在专用端口上使用更简单的握手,而无需重新发明整个协议。

----WebSocket协议RFC 6455

WebSocket协议是一个功能完整的独立协议,可以在浏览器之外使用。尽管如此,它的主要应用程序是作为基于浏览器的应用程序的双向传输。

二进制框架层

客户端和服务器端WebSocket应用程序通过一个面向消息的API进行通信:发送方提供一个任意的UTF-8或二进制有效负载,当整个消息可用时,接收方被通知它的传递。为了实现这一点,WebSocket使用了自定义的二进制帧格式(图17-1),它将每个应用程序消息分解成一个或多个帧,将它们传输到目的地,重新组装它们,并在收到整个消息后通知接收者。


Figure 17-1. WebSocket frame: 2–14 bytes + payload

Frame

通信的最小单位,每个单位包含一个可变长度的帧头和一个可携带全部或部分应用程序消息的有效负载。

Message

映射到逻辑应用程序消息的完整帧序列。

决定将应用程序消息分割成多个框架是由客户机和服务器框架代码的底层实现做出的。因此,应用程序仍然很高兴地不知道各个WebSocket帧或者帧是如何执行的。话虽如此,理解每个WebSocket帧在连线上是如何表示的要点仍然是有用的:

  • 每个帧(FIN)的第一个比特表示该帧是否为消息的最后一个片段。一条消息可能只包含一帧。
  • 操作码(4位)表示传输帧的类型:用于传输应用程序数据的文本(1)或二进制(2)或用于连接活性检查的控制帧,如连接关闭(8)、ping(9)和pong(10)。
  • 掩码位指示负载是否被掩码(仅针对从客户机发送到服务器的消息)。
  • 有效载荷长度用可变长度字段表示:如果0-125,那么这就是有效载荷长度。如果是126,那么下面的两个字节表示一个16位无符号整数,表示帧长度。如果是127,那么下面的8个字节表示一个64位无符号整数,表示帧长度。
  • 屏蔽键包含一个用于屏蔽有效负载的32位值。
  • 有效负载包含应用程序数据和自定义扩展数据(如果客户端和服务器在建立连接时协商了扩展)。

所有客户端发起的帧的有效负载都使用帧头中指定的值来隐藏:这可以防止恶意脚本在客户端执行缓存中毒攻击,攻击那些可能不理解WebSocket协议的中介。有关这次攻击的详细信息,请参考2011年W2SP上的 "Talking to Yourself for Fun and Profit"。

因此,每个服务器发送的WebSocket帧都会产生2-10字节的帧开销。客户端还必须发送一个屏蔽密钥,这将在头文件中增加额外的4个字节,导致开销增加6-14个字节。没有其他元数据可用,例如头字段或关于有效负载的其他信息:所有WebSocket通信都是通过交换帧来执行的,这些帧将有效负载视为应用程序数据的不透明blob。

WebSocket多路复用和堆头阻塞( Head-of-Line Blocking)

WebSocket易受行头阻塞的影响:消息可以被分割成一个或多个帧,但是来自不同消息的帧不能交叉,因为在HTTP/2帧机制中没有等效的“流ID”;参见流、消息和帧)。

因此,一个大消息,即使被分割成多个WebSocket帧,也会阻止与其他消息相关联的帧的传递。如果您的应用程序交付的是对延迟敏感的数据,请注意每个消息的有效负载大小,并考虑将大消息拆分为多个应用程序消息!

核心WebSocket规范中缺乏多路复用也意味着每个WebSocket连接都需要一个专用的TCP连接,这可能成为HTTP/1的一个潜在问题。由于浏览器维护的每个源的连接数量有限而进行的部署;请参阅耗尽客户机和服务器资源。

从好的方面来看,由HyBi工作组开发的“WebSockets多路复用扩展”解决了后一个限制:

有了这个扩展,一个TCP连接可以通过封装带有通道ID标签的帧来提供多个虚拟WebSocket连接……这个多路复用扩展维护独立的逻辑通道,每个逻辑通道提供独立WebSocket连接的完全等价逻辑,包括单独的握手头。

--------------WebSocket多路复用(草案10)

有了这个扩展,多个WebSocket连接(通道)可以在同一个TCP连接上多路复用。然而,每个单独的通道仍然很容易被线头阻塞!因此,一种可能的解决方案是使用不同的通道或专用的TCP连接并行地多路传输多个消息。

最后,注意前面的扩展仅对HTTP/1是必要的。x连接。虽然目前还没有官方规范可以使用HTTP/2传输WebSocket帧,但是这样做会容易得多:HTTP/2有内置的流多路复用,通过在HTTP/2帧机制中封装WebSocket帧,可以在一个会话中传输多个WebSocket连接。

协议的扩展

WebSocket规范允许协议扩展:WebSocket协议的有线格式和语义可以通过新的操作码和数据字段进行扩展。虽然有些不寻常,但这是一个非常强大的特性,因为它允许客户端和服务器在基本的WebSocket框架层之上实现额外的功能,而不需要任何来自应用程序代码的干预或合作。

有一些WebSocket协议扩展的例子吗?负责WebSocket规范开发的HyBi工作组列出了两个正在开发中的官方扩展:

“WebSockets的多路复用扩展”

这个扩展为单独的逻辑WebSocket连接提供了一种共享底层传输连接的方法。

“WebSocket的压缩扩展”

一个用于创建WebSocket扩展的框架,为WebSocket协议添加压缩功能。


如前所述,每个WebSocket连接都需要一个专用的TCP连接,这是低效的。多路复用扩展通过为每个WebSocket帧增加一个额外的“通道ID”来允许多个虚拟的WebSocket通道共享一个TCP连接来解决这个问题。

类似地,基本的WebSocket规范没有为传输数据的压缩提供任何机制或规定:每一帧都携带由应用程序提供的有效负载数据。因此,虽然这对于优化的二进制数据结构来说不是问题,但这可能会导致高字节传输开销,除非应用程序实现了自己的数据压缩和解压缩逻辑。实际上,压缩扩展支持HTTP提供的等效传输编码协商。

要启用一个或多个扩展,客户机必须在初始升级握手时公布它们,服务器必须选择并确认在协商的连接的生命周期中将使用的扩展。作为一个实际的示例,现在让我们仔细看看升级顺序。

WebSocket多路复用和压缩在野外

到2013年中期,WebSocket多路复用还没有被任何流行的浏览器支持。类似地,对压缩的支持也很有限:谷歌Chrome和最新的WebKit浏览器可能会在服务器上发布一个“x-webkit-deflate-frame”扩展。然而,deflate-frame是基于一个过时的修订标准,并将在未来过时。

顾名思义,每帧都是逐帧压缩有效负载内容,这对于可能在多个帧之间分割的大消息不是最优的。因此,压缩扩展的最新版本已经切换到每消息压缩——这是一个好消息。坏消息是每条消息的压缩还处于试验阶段,目前还不能在任何流行的浏览器中使用。

因此,应用程序应该密切关注传输数据的内容类型,并在适用的情况下应用自己的压缩。也就是说,至少要等到本地WebSocket压缩支持在所有流行的浏览器上广泛可用。这对于移动应用程序尤其重要,因为在移动应用程序中,每个不必要的字节都会给用户带来很高的代价。

HTTP升级协商

WebSocket协议提供了很多强大的特性:面向消息的通信、它自己的二进制帧层、子协议协商、可选协议扩展等等。因此,在交换任何消息之前,客户机和服务器必须协商建立连接所需的适当参数。

利用HTTP执行握手提供了几个优点。首先,它使WebSocket与现有的HTTP基础设施兼容:WebSocket服务器可以在端口80和443上运行,这两个端口通常是客户端唯一开放的端口。其次,它允许我们重用和扩展HTTP升级流自定义WebSocket头执行协商:

  • Sec-WebSocket-Version由客户端发送来指示它想要使用的WebSocket协议的版本(对于RFC6455“13”)。如果服务器不支持客户端版本,则必须使用支持版本列表进行响应。
  • Sec-WebSocket-Key客户端发送的自动生成的密钥,它充当服务器的“质询”,以证明服务器支持所请求的协议版本。
  • Sec-WebSocket-Accept包含Sec-WebSocket-Key签名值的服务器响应,证明它理解所请求的协议版本。
  • Sec-WebSocket-Protocol用于协商应用程序子协议:客户端发布支持协议列表;服务器必须使用单个协议名进行应答。
  • Sec-WebSocket-Extensions用于协商用于此连接的WebSocket扩展:客户端声明支持的扩展,服务器通过返回相同的头来确认一个或多个扩展。

有了这些,我们现在就有了执行HTTP升级和协商客户端和服务器之间新的WebSocket连接的所有必要的部分:

GET /socket HTTP/1.1
Host: thirdparty.com
Origin: http://example.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: appProtocol, appProtocol-v2
Sec-WebSocket-Extensions: x-webkit-deflate-message, x-custom-extension
  • 请求执行WebSocket协议升级
  • 客户端使用的WebSocket协议版本
  • 自动生成密钥来验证服务器协议支持
  • 应用程序指定的子协议的可选列表
  • 客户端支持的可选协议扩展列表

就像浏览器中任何其他客户端发起的连接一样,WebSocket请求遵循同源策略:浏览器自动在升级握手中附加源头,远程服务器可以使用CORS来接受或拒绝跨源请求;参见跨源资源共享(CORS)。要完成握手,服务器必须返回一个成功的“交换协议”响应,并确认客户端公布的选择:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Access-Control-Allow-Origin: http://example.com
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: appProtocol-v2
Sec-WebSocket-Extensions: x-custom-extension
  • 确认WebSocket升级的响应代码
  • CORS头指示选择进入跨源连接
  • 签名键值证明协议支持
  • 由服务器选择的应用程序子协议
  • 由服务器选择的WebSocket扩展的列表

所有RFC6455-compatible WebSocket服务器使用相同的算法来计算客户挑战的答案:Sec-WebSocket-Key的内容与独特的GUID连接字符串中定义的标准,SHA1哈希计算,生成的字符串是base - 64编码,并返回给客户端。

一次成功的WebSocket握手至少必须包含协议版本和客户端发送的自动生成的质询值,以及来自服务器的101 HTTP响应代码(交换协议)和一个哈希的质询-响应来确认所选协议版本:

  • 客户端必须发送Sec-WebSocket-Version和Sec-WebSocket-Key。
  • 服务器必须通过返回Sec-WebSocket-Accept来确认协议。
  • 客户端可以通过Sec-WebSocket-Protocol发送应用程序子协议列表。
  • 服务器必须选择一个子协议并通过Sec-WebSocket-Protocol返回。如果服务器不支持任何连接,则连接将中止。
  • 客户端可以发送一个协议扩展列表在Sec-WebSocket-Extensions。
  • 服务器可以确认一个或多个选定的扩展通过Sec-WebSocket-Extensions。如果没有提供扩展,则连接在不提供扩展的情况下继续运行。

最后,一旦前面的握手完成,如果握手成功,连接现在就可以用作交换WebSocket消息的双向通信通道。从这里开始,客户端和服务器之间不再有其他明确的HTTP通信,由WebSocket协议接管。

代理、中介和WebSockets

在实践中,由于安全和策略的原因,许多用户拥有一组受限的开放端口——具体来说端口80 (HTTP)和端口443 (HTTPS)。因此,WebSocket协商是通过HTTP升级流执行的,以确保与现有网络策略和基础设施的最佳兼容性。

然而,正如我们前面提到的代理中介,TLS,和新协议在网络上,许多现有HTTP中介可能不理解新WebSocket协议,从而导致各种各样的失败案例:盲目连接升级,意想不到的WebSocket帧缓冲,内容修改协议的不了解,误分类的WebSocket信息流作为妥协的HTTP连接,等等。

WebSocket密钥和接受握手解决了一些问题:它是一个安全策略,可以防止服务器和中介在没有真正理解WebSocket协议的情况下盲目地“升级”连接。然而,尽管这种预防措施解决了显式代理的一些部署问题,但它对于“透明代理”是不够的,“透明代理”可以在没有通知的情况下分析和修改网络上的数据。

解决方法?建立一个安全的端到端隧道。,用WSS !通过在执行HTTP升级握手之前协商一个TLS会话,客户机和服务器建立一个加密隧道,从而解决前面列出的所有问题。对于移动客户端来说尤其如此,它的流量经常要通过各种代理服务,而这些代理服务在WebSocket中可能不能很好地发挥作用。

相关文章
|
16天前
|
移动开发 JSON Java
Jmeter实现WebSocket协议的接口测试方法
WebSocket协议是HTML5的一种新协议,实现了浏览器与服务器之间的全双工通信。通过简单的握手动作,双方可直接传输数据。其优势包括极小的头部开销和服务器推送功能。使用JMeter进行WebSocket接口和性能测试时,需安装特定插件并配置相关参数,如服务器地址、端口号等,还可通过CSV文件实现参数化,以满足不同测试需求。
78 7
Jmeter实现WebSocket协议的接口测试方法
|
1天前
|
前端开发 JavaScript 安全
深入理解Python Web开发中的前后端分离与WebSocket实时通信技术
在现代Web开发中,前后端分离已成为主流架构,通过解耦前端(用户界面)与后端(服务逻辑),提升了开发效率和团队协作。前端使用Vue.js、React等框架与后端通过HTTP/HTTPS通信,而WebSocket则实现了低延迟的全双工实时通信。本文结合Python框架如Flask和Django,探讨了前后端分离与WebSocket的最佳实践,包括明确接口规范、安全性考虑、性能优化及错误处理等方面,助力构建高效、实时且安全的Web应用。
9 2
|
1天前
|
前端开发 Python
前后端分离的进化:Python Web项目中的WebSocket实时通信解决方案
在现代Web开发领域,前后端分离已成为一种主流架构模式,它促进了开发效率、提升了应用的可维护性和可扩展性。随着实时数据交互需求的日益增长,WebSocket作为一种在单个长连接上进行全双工通讯的协议,成为了实现前后端实时通信的理想选择。在Python Web项目中,结合Flask框架与Flask-SocketIO库,我们可以轻松实现WebSocket的实时通信功能。
8 2
|
2天前
|
Cloud Native 持续交付 云计算
探索云原生架构:构建现代应用的新范式
在当今数字化浪潮中,云原生架构以其敏捷性、弹性和可扩展性成为企业技术转型的核心驱动力。本文将引领读者深入理解云原生的概念,剖析其关键技术组件——微服务、容器化、DevOps实践及持续交付/持续部署流程,并揭示这些技术如何相互协作,共同构建高效、可靠且易于管理的现代软件系统。通过对云原生架构的全面解读,我们旨在为开发者、架构师乃至企业决策者提供有价值的见解与指导,助力其在快速变化的市场环境中保持竞争力。
|
7天前
|
Kubernetes Cloud Native Serverless
探索云原生技术:从基础架构到应用实践
本文深入探讨了云原生技术的各个方面,包括其定义、核心原则、关键技术组件以及在现代企业中的应用。通过分析云原生如何推动数字化转型和提高业务敏捷性,文章旨在为读者提供对这一领域的全面了解和实际应用的指导。
33 7
|
4天前
|
前端开发 API Python
WebSocket技术详解:如何在Python Web应用中实现无缝实时通信
在Web开发的广阔领域中,实时通信已成为许多应用的核心需求。传统的HTTP请求-响应模型在实时性方面存在明显不足,而WebSocket作为一种在单个长连接上进行全双工通信的协议,为Web应用的实时通信提供了强有力的支持。本文将深入探讨WebSocket技术,并通过一个Python Web应用的案例分析,展示如何在Python中利用WebSocket实现无缝实时通信。
14 2
|
9天前
|
Kubernetes Cloud Native 持续交付
深入理解云原生技术及其在现代IT架构中的应用
【9月更文挑战第18天】云原生技术,作为推动企业数字化转型的引擎,正以它独特的魅力重塑着信息技术的未来。本文将带你一探究竟,从云原生的基础概念出发,逐步深入到其核心组件、设计理念以及如何在实际应用中发挥巨大作用。你将了解到容器化、微服务架构、持续集成与持续部署(CI/CD)等关键实践,并见证它们如何帮助企业构建更加灵活、高效和可靠的应用。
|
15天前
|
机器学习/深度学习 测试技术 数据处理
KAN专家混合模型在高性能时间序列预测中的应用:RMoK模型架构探析与Python代码实验
Kolmogorov-Arnold网络(KAN)作为一种多层感知器(MLP)的替代方案,为深度学习领域带来新可能。尽管初期测试显示KAN在时间序列预测中的表现不佳,近期提出的可逆KAN混合模型(RMoK)显著提升了其性能。RMoK结合了Wav-KAN、JacobiKAN和TaylorKAN等多种专家层,通过门控网络动态选择最适合的专家层,从而灵活应对各种时间序列模式。实验结果显示,RMoK在多个数据集上表现出色,尤其是在长期预测任务中。未来研究将进一步探索RMoK在不同领域的应用潜力及其与其他先进技术的结合。
49 4
|
15天前
|
存储 搜索推荐 数据库
MarkLogic在微服务架构中的应用:提供服务间通信和数据共享的机制
随着微服务架构的发展,服务间通信和数据共享成为关键挑战。本文介绍MarkLogic数据库在微服务架构中的应用,阐述其多模型支持、索引搜索、事务处理及高可用性等优势,以及如何利用MarkLogic实现数据共享、服务间通信、事件驱动架构和数据分析,提升系统的可伸缩性和可靠性。
21 5
|
15天前
|
运维 Cloud Native Devops
云原生架构的崛起与实践云原生架构是一种通过容器化、微服务和DevOps等技术手段,帮助应用系统实现敏捷部署、弹性扩展和高效运维的技术理念。本文将探讨云原生的概念、核心技术以及其在企业中的应用实践,揭示云原生如何成为现代软件开发和运营的主流方式。##
云原生架构是现代IT领域的一场革命,它依托于容器化、微服务和DevOps等核心技术,旨在解决传统架构在应对复杂业务需求时的不足。通过采用云原生方法,企业可以实现敏捷部署、弹性扩展和高效运维,从而大幅提升开发效率和系统可靠性。本文详细阐述了云原生的核心概念、主要技术和实际应用案例,并探讨了企业在实施云原生过程中的挑战与解决方案。无论是正在转型的传统企业,还是寻求创新的互联网企业,云原生都提供了一条实现高效能、高灵活性和高可靠性的技术路径。 ##
24 3