7 关闭连接7.1 定义7.1.1 关闭 WebSocket 连接为了关闭 WebSocket 连接,一端可以关闭底层的 TCP 连接。一端在关闭连接的时候必须干净的关闭,比如 TLS 会话,尽可能的丢弃所有已经接收但是尚未处理的字节。一端可以在需要的时候以任意的理由去关闭连接,比如在收到攻击时。
底层的 TCP 连接,在一般情况下应该由服务端先进行关闭,而客户端则需要在一段时间内等待服务端的 TCP 关闭,如果超过了客户端的等待时间,客户端则可以关闭 TCP 连接。
一个以使用 Berkeley sockets 的 C 语言的例子演示如何干净的关闭连接:首先一端需要调用对 socket 调用 shutdown() 函数,并以 SHUT_WR 为函数的参数,然后调用 recv() 函数直到其返回值为 0,最后调用 close() 函数关闭 socket。
7.1.2 开始 WebSocket 关闭握手为了关闭开始 WebSocket 关闭握手,需要关闭的一端必须选择一个状态码(第 7.4 节)/code/ 和可选的关闭原因 (第 7.1.6 节)/reason/,然后按照第 5.5.1 节中的描述发送一个关闭帧,帧的状态码以及原因就是之前选取的 /code/ 和 /reason/。一旦一端发送并接收到了关闭帧,就可以按照第 7.1.1 节中定义的内容关闭 WebSocket 连接。
7.1.3 WebSocket 关闭握手已经开始一旦任何一端发送或者接收到关闭帧,就表明 WebSocket 关闭握手已经开始,并且 WebSocket 连接的状态变为 CLOSING。
7.1.4 WebSocket 连接已经关闭当底层的 TCP 连接已经关闭时,就表明 WebSocket 连接已经关闭,并且 WebSocket 连接的状态变为 CLOSED。如果 TCP 连接在 WebSocket 关闭握手完成之后才进行关闭,就说明关闭是干净(cleanly)的。否则的话就说明 WebSocket 连接已经关闭,但不是干净地(cleanly)。
7.1.5 WebSocket 连接关闭代码与第 5.5.1 节和第 7.4 节中定义的一样,一个关闭帧可以包含一个关闭状态码,以此表明关闭的原因。WebSocket 的关闭可以由任意一端发起,或者同时发起。返回的关闭帧的状态码与接收到的关闭帧的状态码相同。如果关闭帧没有包含状态码,那么就认为其状态码是 1005。如果一端发现 WebSocket 连接已经关闭但是没有收到关闭帧,那么就认为此时的状态码是 1006。
注意:两端的关闭帧的状态码不必相同。比如,如果远程的一端发送了一个关闭帧,但是本地的应用程序还没有读取位于接收缓存中的关闭帧,并且应用程序也发送了一个关闭帧,那么两端都将会达到 “发送了” 和 “接收到” 关闭帧的状态。每一端都会看到来自另一端的具有不同状态码的关闭帧。因此,两端可以不必要求发送和接收到的关闭帧的状态码是相同的,这样两端就可以大概同时进行 WebSocket 连接的关闭了。
7.1.6 WebSocket 连接关闭原因与第 5.5.1 节和第 7.4 节中定义的相同,关闭帧可以包含一个状态码,并且在状态码之后可以跟随以 UTF-8 编码的数据,具体这些数据应该如何被解释依赖于对端的实现,本协议并没有明确的定义。每一端都可以发起 WebSocket 关闭,或者同时发起。WebSocket 连接关闭原因的定义就是跟随在关闭状态码之后的以 UTF-8 编码的数据,响应的关闭帧中的 /reason/ 内容来自请求的关闭帧中 /reason/,并与之相同。如果没有定义这些 UTF-8 数据,那么关闭的原因就是空字符串。
注意:遵循第 7.1.5 节中描述的逻辑,两端不必要求发送和接收的关闭帧的 /reason/ 是相同的。
7.1.7 将 WebSocket 连接标记为失败因为某种算法或者特定的需求使得一端需要将 WebSocket 连接表示位失败。为了达到这个目的,客户端必须关闭 WebSocket 连接,并且可以将问题以适当的方式反馈给用户(对于开发者来说可能非常重要)。同样的,服务端为了达到这个目的也必须关闭 WebSocket 连接,并且使用日志记录下发生的问题。
如果在希望将 WebSocket 连接标记为失败之前,WebSocket 连接已经建立的话,那么一端在关闭 WebSocket 连接之前应该发送关闭帧,并带上适当的状态码(第 7.4 节)。如果一端认为另一端不可能有能力去接受和处理关闭帧时,比如 WebSocket 连接尚未建立,那么可以省略发送关闭帧的过程。如果一端标记了 WebSocket 连接为失败的,那么它不可以再接受和处理来自远程的数据(包括响应一个关闭帧)。
除了上面的情况或者应用层需要(比如,使用了 WebSocket API 的脚本),客户端不应该关闭连接。 |