این کار باعث حذف صفحه ی "5. 数据帧"
می شود. لطفا مطمئن باشید.
5.1. 概述
在WebSocket协议中,数据通过一系列帧进行传输。为了避免混淆网络中介(如拦截代理)以及出于进一步在第10.3节讨论的安全原因,客户端必须对其发送给服务器的所有帧进行掩码处理(详见第5.3节了解更多细节)。(注意,无论WebSocket协议是否运行在TLS之上,都要进行掩码处理。)服务器在接收到未经掩码处理的帧时,必须关闭连接。在这种情况下,服务器可以发送一个带有1002(协议错误)状态码的关闭帧,如第7.4.1节所定义。服务器不得对其发送给客户端的任何帧进行掩码处理。如果客户端检测到一个被掩码处理的帧,它必须关闭连接。在这种情况下,它可以使用状态码1002(协议错误),如第7.4.1节所定义。(这些规则在未来的规范中可能会放宽。)
基本帧协议定义了一种帧类型,带有操作码、有效载荷长度和为“扩展数据”和“应用数据”指定的位置,这些共同定义了“有效载荷数据”。某些位和操作码保留用于协议的未来扩展。
数据帧可以在开放握手完成后和该端点发送关闭帧(第5.5.1节)之前的任何时间由客户端或服务器传输。
5.2. 基础帧协议
此数据传输部分的线路格式由本节详细给出的ABNF [RFC5234] 描述。(注意,与本文档的其他部分不同,本节中的ABNF操作的是位组。每组位的长度在注释中指示。当在线路上编码时,最高有效位是ABNF中最左边的)。下图给出了帧结构的高级概述。如果下图与本节后面指定的ABNF之间存在冲突,以图为准。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
FIN: 1位
表示这是消息中的最后一个片段。第一个片段也可能是最后一个片段。
RSV1, RSV2, RSV3: 每个1位
除非协商了定义非零值含义的扩展,否则必须为0。如果接收到非零值,并且没有协商的扩展定义了这样的非零值的含义,接收端点必须_失败WebSocket连接_。
Opcode: 4位
定义了“有效载荷数据”的解释。如果接收到未知的操作码,接收端点必须_失败WebSocket连接_。定义了以下值。
Mask: 1位
定义“有效载荷数据”是否被掩码处理。如果设置为1,则掩码键存在于掩码键中,并且用于根据第5.3节解除“有效载荷数据”的掩码。所有从客户端发送到服务器的帧都将此位设置为1。
有效载荷长度:7位,7+16位,或7+64位
“有效载荷数据”的长度,以字节为单位:如果是0-125,那就是有效载荷长度。如果是126,接下来的2字节解释为一个16位无符号整数是有效载荷长度。如果是127,接下来的8字节解释为一个64位无符号整数(最高有效位必须为0)是有效载荷长度。多字节长度量以网络字节顺序表示。注意,在所有情况下,必须使用最少的字节数来编码长度,例如,不能将124字节长的字符串的长度编码为序列126, 0, 124。有效载荷长度是“扩展数据”长度+“应用数据”长度。“扩展数据”的长度可能为零,在这种情况下,有效载荷长度就是“应用数据”的长度。
掩码键:0或4字节
所有从客户端发送到服务器的帧都通过包含在帧内的32位值进行掩码处理。如果掩码位设置为1,则此字段存在;如果掩码位设置为0,则此字段不存在。有关客户端到服务器掩码的更多信息,请参见第5.3节。
有效载荷数据:(x+y)字节
“有效载荷数据”定义为“扩展数据”与“应用数据”连接在一起。
扩展数据:x字节
除非协商了扩展,“扩展数据”为0字节。任何扩展都必须指定“扩展数据”的长度,或者如何计算该长度,以及如何在开放握手期间协商扩展的使用。如果存在,“扩展数据”包含在总有效载荷长度中。
应用数据:y字节
任意的“应用数据”,占据帧中任何“扩展数据”之后的剩余部分。“应用数据”的长度等于有效载荷长度减去“扩展数据”的长度。
基础帧协议由以下ABNF [RFC5234] 正式定义。重要的是要注意,这些数据的表示形式是二进制的,而不是ASCII字符。因此,长度为1位且取值为%x0 / %x1的字段表示为单个位的值为0或1,而不是代表ASCII编码中的字符“0”或“1”的完整字节(八位字节)。长度为4位且值在%x0-F之间的字段再次由4位表示,而不是由ASCII字符或具有这些值的完整字节(八位字节)表示。[RFC5234] 没有指定字符编码:“规则解析为一串终端值,有时称为字符。在ABNF中,字符仅仅是一个非负整数。在某些上下文中,将指定值到字符集(如ASCII)的特定映射(编码)。”这里,指定的编码是二进制编码,其中每个终端值以指定的位数编码,这对每个字段都是不同的。
5.3. 客户端到服务器的掩码处理
一个被掩码处理的帧必须将字段 frame-masked 设置为1,如第5.2节所定义。
掩码键完全包含在帧内,如第5.2节中定义的 frame-masking-key。它用于掩码处理同一节中定义的“有效载荷数据”(frame-payload-data),包括“扩展数据”和“应用数据”。
掩码键是客户端随机选择的32位值。当准备一个被掩码处理的帧时,客户端必须从允许的32位值集合中选择一个新的掩码键。掩码键需要是不可预测的;因此,掩码键必须来自一个强熵源,并且给定帧的掩码键不得使服务器/代理能够简单地预测后续帧的掩码键。掩码键的不可预测性对于防止恶意应用的作者选择出现在线路上的字节至关重要。RFC 4086 [RFC4086] 讨论了对于安全敏感应用来说什么构成了合适的熵源。
掩码处理不影响“有效载荷数据”的长度。要将被掩码处理的数据转换为未掩码处理的数据,或反之亦然,应用以下算法。无论转换的方向如何,都应用相同的算法,例如,掩码处理数据的步骤与解除掩码处理数据的步骤相同。
变换后数据的第i个字节("transformed-octet-i")是原始数据的第i个字节("original-octet-i")与掩码键中索引为i模4的字节("masking-key-octet-j")的异或(XOR)结果:
j = i MOD 4
transformed-octet-i = original-octet-i XOR masking-key-octet-j
帧中指示的有效载荷长度(frame-payload-length)不包括掩码键的长度。它是“有效载荷数据”的长度,例如,掩码键后面的字节数。
5.4. 分片
分片的主要目的是允许在开始消息时不知道消息的大小而不必缓冲该消息就能发送消息。如果不能对消息进行分片,那么端点将不得不缓冲整个消息,以便在发送第一个字节之前计算其长度。通过分片,服务器或中介可以选择一个合理大小的缓冲区,并且当缓冲区满时,将一个片段写入网络。
分片的次要用例是多路复用,其中不希望一个逻辑通道上的大消息垄断输出通道,因此多路复用需要能够将消息分割成更小的片段以更好地共享输出通道。(注意,多路复用扩展在本文档中没有描述。)
除非扩展另有规定,否则帧没有语义含义。如果客户端和服务器没有协商扩展,或者协商了一些扩展,但中介理解所有协商的扩展并知道如何在这些扩展存在的情况下合并和/或分割帧,那么中介可能会合并和/或分割帧。这意味着在没有扩展的情况下,发送者和接收者不得依赖于特定帧边界的存在。
分片遵循以下规则:
示例:对于作为三个片段发送的文本消息,第一个片段将有一个操作码0x1和一个清除的FIN位,第二个片段将有一个操作码0x0和一个清除的FIN位,第三个片段将有一个操作码0x0和一个设置的FIN位。
注意:如果不能插入控制帧,例如,如果在一个大消息后面,ping的延迟会非常长。因此,要求在分片消息中间处理控制帧。
实现注意:在没有任何扩展的情况下,接收者不必缓冲整个帧就能处理它。例如,如果使用流API,可以将帧的一部分交付给应用程序。然而,请注意,这个假设可能不适用于所有未来的WebSocket扩展。
5.5. 控制帧
控制帧通过操作码来识别,其中操作码的最高有效位为1。目前为控制帧定义的操作码包括0x8(关闭)、0x9(Ping)和0xA(Pong)。操作码0xB-0xF保留用于将来定义的进一步控制帧。
控制帧用于通信有关WebSocket的状态。控制帧可以在分片消息的中间插入。
所有控制帧必须有125字节或更少的有效载荷长度,并且不能被分片。
5.5.1. 关闭
关闭帧包含操作码0x8。
关闭帧可能包含一个体(帧的“应用数据”部分),该体指示关闭的原因,例如端点关闭、端点收到过大的帧,或端点收到的帧不符合端点期望的格式。如果有体,体的前两个字节必须是一个2字节无符号整数(网络字节顺序),表示在第7.4节中定义的状态码/code/。在2字节整数之后,体可能包含UTF-8编码的数据/value/reason/,其解释不由本规范定义。这些数据不一定是人类可读的,但可能对调试或传递与打开连接的脚本相关的信息有用。由于数据不保证是人类可读的,客户端不得向最终用户显示它。
从客户端发送到服务器的关闭帧必须按照第5.3节进行掩码处理。
应用在发送关闭帧后不得再发送任何数据帧。
如果端点收到关闭帧而之前没有发送关闭帧,端点必须发送一个关闭帧作为响应。(发送响应关闭帧时,端点通常回显它收到的状态码。)它应该尽快这样做。端点可能会延迟发送关闭帧,直到其当前消息被发送(例如,如果分片消息的大部分已经发送,端点可能会在发送关闭帧之前发送剩余的片段)。然而,不能保证已经发送关闭帧的端点将继续处理数据。
在发送和接收关闭消息后,端点认为WebSocket连接已关闭,并且必须关闭底层的TCP连接。服务器必须立即关闭底层的TCP连接;客户端应该等待服务器关闭连接,但在发送和接收关闭消息后,可以在任何时候关闭连接,例如,如果在合理的时间内没有从服务器收到TCP关闭。
如果客户端和服务器同时发送关闭消息,两个端点都将发送和接收关闭消息,并应该认为WebSocket连接已关闭,并关闭底层的TCP连接。
5.5.2. Ping
Ping帧包含操作码0x9。
Ping帧可能包含“应用数据”。
在收到Ping帧后,端点必须发送一个Pong帧作为响应,除非它已经收到了关闭帧。它应该尽快以Pong帧作为响应。Pong帧在第5.5.3节中讨论。
在连接建立后和关闭之前的任何时间,端点都可以发送Ping帧。
注意:Ping帧可以用作保活信号或用来验证远程端点是否仍然响应。
5.5.3. Pong
Pong帧包含操作码0xA。
第5.5.2节详细说明了适用于Ping和Pong帧的要求。
作为对Ping帧的响应发送的Pong帧必须具有与被回复的Ping帧的消息体中找到的“应用数据”完全相同。
如果端点收到Ping帧,并且尚未对之前的Ping帧发送Pong帧作为响应,端点可以选择仅对最近处理的Ping帧发送Pong帧。
Pong帧可以不经请求发送。这作为单向心跳信号。对不经请求的Pong帧不期望响应。
5.6. 数据帧
数据帧(例如,非控制帧)通过操作码来识别,其中操作码的最高有效位为0。目前为数据帧定义的操作码包括0x1(文本)、0x2(二进制)。操作码0x3-0x7保留用于将来定义的进一步非控制帧。
数据帧携带应用层和/或扩展层数据。操作码决定了数据的解释:
文本
“有效载荷数据”是编码为UTF-8的文本数据。注意,特定的文本帧可能包含部分UTF-8序列;然而,整个消息必须包含有效的UTF-8。重组消息中的无效UTF-8按照第8.1节中描述的方式处理。
二进制
“有效载荷数据”是任意二进制数据,其解释完全由应用层决定。
5.7. 示例
单帧未掩码文本消息
单帧掩码文本消息
分片未掩码文本消息
未掩码Ping请求和掩码Ping响应
单帧未掩码256字节二进制消息
单帧未掩码64KiB二进制消息
5.8. 可扩展性
该协议旨在允许扩展,这将为基本协议增加功能。连接的端点必须在开放握手期间协商任何扩展的使用。本规范为扩展提供了操作码0x3至0x7和0xB至0xF、“扩展数据”字段,以及帧头的frame-rsv1、frame-rsv2和frame-rsv3位。扩展的协商在第9.1节中进一步详细讨论。以下是一些预期的扩展用途。这个列表既不完整也不规定性。
این کار باعث حذف صفحه ی "5. 数据帧"
می شود. لطفا مطمئن باشید.