RFC-6455 WebSocket Protocol in chinese

7. 关闭连接

7.1. 定义

7.1.1. 关闭WebSocket连接

为 _关闭WebSocket连接_,端点需关闭底层TCP连接。 端点应该使用一个方法完全地关闭TCP连接,以及 TLS 会话,如果合适,丢弃任何可能已经接收的尾随的字节。 当必要时端点可以通过任何可用的手段关闭连接,例如当受到攻击时。

底层 TCP 连接,在大多数正常情况下,应该首先被服务器关闭,所以它持有 TIME_WAIT 状态而不是客户端(因为这会防止它在2个报文最大生存时间(2MLS)内重新打开连接,然而当一个新的带有更高的 seq number 的 SYN 时没有对应的服务器影响 TIME_WAIT连接被立即重新打开)。 在异常情况下(例如在一个合理的时间量后没有接收到服务器的TCP Close)客户端可以发起TCP Close。 因此,当服务器被指示 _关闭 WebSocket 连接_,它应该立即发起一个TCP Close,且当客户端被指示也这么做时,它应该等待服务器的一个TCP Close。

例如一个如何使用Berkeley socket 在 C 中得到完全地关闭的例子,一端会在 socket 上以 SHUT_WR 调用 shutdown(),调用 recv() 直到获得一个指示那个节点也已经执行了一个有序关闭的0返回值,且最终在socket上调用 close() 方法。

7.1.2. 启动WebSocket关闭阶段握手

为了_启动 WebSocket 关闭阶段握手_,其带有一个状态码(7.4节)/code/和一个可选的关闭原因(7.1.6节)/reason/,一个端点必须按照 5.5.1 节的描述发送一个 Close 控制帧,其状态码设置为/code/且其关闭原因设置为/reason/。 一旦一个端点已经发送并接收到一个Close控制帧,那个端点应该按照7.1.1节的描述\关闭 WebSocket 连接\

7.1.3. WebSocket关闭阶段握手已启动

一旦发送或接收到一个Close控制帧,这就是说,_WebSocket 关闭阶段握手已启动_,且 WebSocket 连接处于 CLOSING 状态。

7.1.4. WebSocket已关闭

当底层TCP连接已关闭,这就是说 _WebSocket连接已关闭_ 且 WebSocket 连接处于 CLOSED 状态。 如果 TCP 连接在 WebSocket 关闭阶段已经完成后被关闭,WebSocket连接被说成已经 _完全地_ 关闭了。 如果WebSocket连接不能被建立,这就是说,_WebSocket连接关闭了_,但不是 _完全的_ 。

7.1.5. WebSocket连接关闭代码

按照 5.5.1 和 7.4 节的定义,一个 Close 控制帧可以包含一个表示关闭原因的状态码。 一个正关闭的 WebSocket 连接可以同时由两个端点初始化。 _WebSocket连接Close Code_ 定义为包含在由实现该协议的应用接收到的第一个 Close 控制帧的状态码(7.4节)。 如果这个 Close 控制帧不包含状态码,_WebSocket 连接 Close Code_ 被认为是 1005。 如果 _WebSocket连接已经关闭_ 且端点没有接收到Close状态码(例如可能发生在底层传输连接丢失时),_WebSocket 连接 Close Code_ 被认为是 1006。

注意:两个端点可以有不一致的 _WebSocket连接关闭代码_。 例如,如果远程端点发送了一个 Close 帧,但本地应用还没有从它的 socket 接收缓冲区中读到包含 Close 帧的数据,且本地应用独立地决定关闭连接和发送一个 Close 帧,两个端点都将发送和接收 Close 帧且将不发送更多的 Close 帧。 每一个端点将看见另一端发送的以 _WebSocket连接关闭代码_ 结束的状态码。 例如,在两个端点独立且在大致相同的时间同时 _开启WebSocket关闭阶段握手_ 的情况下,两个端点可以有不一致的 _WebSocket连接关闭代码_ 是可能的。

7.1.6. WebSocket 连接关闭原因

按照 5.5.1 和 7.4 节的定义,一个 Close 控制帧可以包含一个指示关闭原因的状态码,接着是 UTF-8 编码的数据,上述数据留给断点解释且本协议没有定义。 WebSocket 连接的关闭可以被任何一个端点初始化,可能同时发生。 _WebSocket 连接关闭原因_ 由跟在包含在实现该协议的应用接收到的第一个 Close 控制帧状态码(7.4节)后边的 UTF-8 编码的数据定义。 如果 Close 控制帧中没有这样的数据,_WebSocket连接关闭原因_ 是空字符串。

注意:按照7.1.5节指出的相同的逻辑,两个端点可以有不一致的 _WebSocket 连接关闭原因_ 。

7.1.7. 失败WebSocket连接

某些算法和规范要求端点 _失败 WebSocket 连接_ 。 要做到这一点,客户端必须 _关闭WebSocket连接_,并可以以适当的方式把问题报告给用户(这将对开发人员非常有用的)。

同样的,为了做到这一点,服务器必须_关闭WebSocket连接_,并应该记录下问题。

如果 _已建立的WebSocket连接_ 在端点需要 _失败WebsSocket连接_ 之前,端点应该在处理 _关闭WebSocket连接_ 之前发送一个带有适当状态码的 Close 帧(7.4节)。

如果端点认为另一边不太可能收到并处理关闭帧可以省略发送一个关闭帧,因为错误的性质,导致 WebSocket 连接失败摆在首要位置。 端点必须在被指示为 _失败WebSocket端点_ 之后不继续尝试处理来自远程端点的数据(包括响应关闭帧)。

除上边指出的或由应用层指定的(例如,使用WebSocket API 的脚本),客户端应该关闭连接。

7.2. 异常关闭

7.2.1. 客户端发起的关闭

某些算法,尤其在打开阶段握手期间,需要客户端 _失败WebSocket连接_ 。 为了做到这一点,客户端必须按照7.1.7节定义的那样 _失败WebSocket连接_ 。

如果在任何时候,底层的传输层连接意外丢失,客户端必须 _失败WebSocket连接_ 。 除上边指出的或由应用层指定的(例如,使用WebSocket API的脚本),客户端应该关闭连接。

7.2.2. 服务端发起的关闭

某些算法需要或推荐服务端在打开阶段握手期间 _中断 WebSocket 连接_。 为了做到这一点,服务端必须简单地 _关闭WebSocket连接_(7.1.1节)。

7.2.3. 从异常关闭中恢复

异常关闭可能由任何原因引起。 这样的关闭可能是一个瞬时错误导致的,在这种情况下重新连接可能导致一个好的连接和一个重新开始的正常操作。 这样的关闭也可能是一个非瞬时问题的导致的,在这种情况下如果每个部署的客户端遇到异常关闭并立即且持续地的尝试重新连接,服务端可能会因为大量的客户端尝试重新连接遇到的拒绝服务攻击。 这种情况的最终结果可能是服务不能及时的恢复或恢复是更加困难。

为了避免这个,当客户端遇到本节描述的异常关闭之后尝试重新连接时,应该使用某种形式的补偿。

第一个重新连接尝试应该延迟一个随机的时间量。 这种随机延迟的参数的选择留给客户端决定;一个可随机选择的的值在 0 到 5 秒是一个合理的初始延迟,不过客户端可以选择不同的间隔由于其选择一个延迟长度基于实现经验和特定的应用 。

第一次重新连接尝试失败,随后的重新连接尝试应该延迟递增的时间量,使用的方法如截断二进制指数退避算法。

7.3. 正常连接关闭

服务端在需要时可能关闭 WebSocket 连接。 客户端不能随意关闭 WebSocket 连接。 在这两种情况下,端点通过如下过程 _开始WebSocket关闭握手_ 初始化一个关闭(7.1.2节)。

7.4. 状态码

当关闭一个已经建立的连接(例如,当在打开阶段握手已经完成后发送一个关闭帧),端点可以表明关闭的原因。 由端点解释这个原因,并且端点应该给这个原因采取动作,本规范是没有定义的。 本规范定义了一组预定义的状态码,并指定哪些范围可以被扩展、框架和最终应用使用。 状态码和任何相关的文本消息是关闭帧的可选的组件。

7.4.1.定义的状态码

当发送关闭帧时端点可以使用如下预定义的状态码。

  • 1000

    1000表示正常关闭,意思是建议的连接已经完成了。

  • 1001

    1001表示端点“离开”(going away),例如服务器关闭或浏览器导航到其他页面。

  • 1002

    1002表示端点因为协议错误而终止连接。

  • 1003

    1003表示端点由于它收到了不能接收的数据类型(例如,端点仅理解文本数据,但接收到了二进制消息)而终止连接。

  • 1004

    保留。可能在将来定义其具体的含义。

  • 1005

    1005 是一个保留值,且不能由端点在关闭控制帧中设置此状态码。 它被指定用在期待一个用于表示没有状态码是实际存在的状态码的应用中。

  • 1006

    1006 是一个保留值,且不能由端点在关闭控制帧中设置此状态码。 它被指定用在期待一个用于表示连接异常关闭的状态码的应用中。

  • 1007

    1007 表示端点因为消息中接收到的数据是不符合消息类型而终止连接(比如,文本消息中存在非UTF-8[RFC3629]数据)。

  • 1008

    1008 表示端点因为接收到的消息违反其策略而终止连接。 这是一个当没有其他合适状态码(例如1003或1009)或如果需要隐藏策略的具体细节时能被返回的通用状态码。

  • 1009

    1009 表示端点因接收到的消息对它的处理来说太大而终止连接。

  • 1010

    1010 表示端点(客户端)因为它期望服务器协商一个或多个扩展,但服务器没有在WebSocket握手响应消息中返回它们而终止连接。 所需要的扩展列表应该出现在关闭帧的/reason/部分。

    注意,这个状态码不能被服务器端使用,因为它可以失败WebSocket握手。

  • 1011

    1011 表示服务器端因为遇到了一个不期望的情况使它无法满足请求而终止连接。

  • 1015

    1015 是一个保留值,且不能由端点在关闭帧中被设置为状态码。 它被指定用在期待一个用于表示连接由于执行 TLS 握手失败而关闭的状态码的应用中(比如,服务器证书不能验证)。

7.4.2.保留的状态码范围

  • 0-999

    0-999 范围内的状态码不被使用。

  • 1000-2999

    1000-2999 范围内的状态码保留给本协议、其未来的修订和一个永久的和现成的公共规范中指定的扩展的定义。

  • 3000-3999

    3000-3999 范围内的状态码保留给库、框架和应用使用。 这些状态码直接向 IANA 注册。本规范未定义这些状态码的解释。

  • 4000-4999

    4000-4999 范围内的状态码保留用于私有使用且因此不能被注册。 这些状态码可以被在 WebSocket 应用之间的先前的协议使用。 本规范未定义这些状态码的解释。