7. Closing the Connection
7.关闭连接
7.1. Definitions
7.1 术语
7.1.1. Close the WebSocket Connection
7.1.1 关闭WebSocket连接
To _Close the WebSocket Connection_, an endpoint closes the
underlying TCP connection. An endpoint SHOULD use a method that
cleanly closes the TCP connection, as well as the TLS session, if
applicable, discarding any trailing bytes that may have been
received. An endpoint MAY close the connection via any means
available when necessary, such as when under attack.
The underlying TCP connection, in most normal cases, SHOULD be closed
first by the server, so that it holds the TIME_WAIT state and not the
client (as this would prevent it from re-opening the connection for 2
maximum segment lifetimes (2MSL), while there is no corresponding
server impact as a TIME_WAIT connection is immediately reopened upon
a new SYN with a higher seq number). In abnormal cases (such as not
having received a TCP Close from the server after a reasonable amount
of time) a client MAY initiate the TCP Close. As such, when a server
is instructed to _Close the WebSocket Connection_ it SHOULD initiate
a TCP Close immediately, and when a client is instructed to do the
same, it SHOULD wait for a TCP Close from the server.
As an example of how to obtain a clean closure in C using Berkeley
sockets, one would call shutdown() with SHUT_WR on the socket, call
recv() until obtaining a return value of 0 indicating that the peer
has also performed an orderly shutdown, and finally call close() on
the socket.
要关闭WebSoket连接,终端需要关闭底层的TCP连接。终端需要使用一个方法干净的关闭TCP连接、TLS会话,如果可能的话,丢弃所有已收到数据之后的数据。必要的情况下,终端可以使用任何方式关闭连接,比如受到攻击时。在大多数情况下,底层的TCP连接应该由服务端关闭,因为服务端持有TIME_WAIT状态而不是客户端(客户端将防止其在2段最大生命周期的间隔后才能打开连接,当没有对应的服务端影响作为等待时间时,连接会用一个更高的seq在一个新的SYN上立即打开)。反常情况下(例如在一个合理的时候后没有从服务端接收到TCP关闭信号)客户端可能会开启TCP关闭。因此,当服务端打算要关闭WebSocket连接的时候,它需要立即启动TCP关闭,当客户打算这么做的时候,它应该等服务端发送TCP关闭。举个例子,在C中使用Berkeley sockets如何执行干净的关闭,需要在socket上调用shutdown(SHUT_WR)方法,然后调用recv方法直到获得返回值0,这标志着对方也已经按照顺序进行了shutdown操作,最后调用close()。
7.1.2. Start the WebSocket Closing Handshake
To _Start the WebSocket Closing Handshake_ with a status code
(Section 7.4) /code/ and an optional close reason (Section 7.1.6)
/reason/, an endpoint MUST send a Close control frame, as described
in Section 5.5.1, whose status code is set to /code/ and whose close
reason is set to /reason/. Once an endpoint has both sent and
received a Close control frame, that endpoint SHOULD _Close the
WebSocket Connection_ as defined in Section 7.1.1.
7.1.2 开始WebSocket关闭握手
开始一个WebSocket关闭握手需要包含一个状态码和一个可选的关闭原因,客户端必须发送一个关闭控制数据包,其中code字段标识状态码,reason字段标识关闭原因。一旦终端发送并接收了关闭控制数据包,终端需要关闭WebSocket连接。
7.1.3. The WebSocket Closing Handshake is Started
Upon either sending or receiving a Close control frame, it is said
that _The WebSocket Closing Handshake is Started_ and that the
WebSocket connection is in the CLOSING state.
7.1.3 WebSocket关闭握手已经启动
一旦接收或发送一个关闭控制数据包,标识着WebSocket关闭握手已经启动,WebSocket连接处于CLOSING状态。
7.1.4. The WebSocket Connection is Closed
When the underlying TCP connection is closed, it is said that _The
WebSocket Connection is Closed_ and that the WebSocket connection is
in the CLOSED state. If the TCP connection was closed after the
WebSocket closing handshake was completed, the WebSocket connection
is said to have been closed _cleanly_.
If the WebSocket connection could not be established, it is also said
that _The WebSocket Connection is Closed_, but not _cleanly_.
7.1.4. WebSocket连接已经关闭
当底层的TCP连接关闭后就意味着WebSocket连接已经关闭,WebSocket连接处于CLOSED状态。假如TCP连接在WebSocket关闭握手结束后关闭,则意味着WebSocket连接被干净的关闭了。
7.1.5. The WebSocket Connection Close Code
7.1.5 WebSocket连接关闭码
As defined in Sections 5.5.1 and 7.4, a Close control frame may
contain a status code indicating a reason for closure. A closing of
the WebSocket connection may be initiated by either endpoint,
potentially simultaneously. _The WebSocket Connection Close Code_ is
defined as the status code (Section 7.4) contained in the first Close
control frame received by the application implementing this protocol.
If this Close control frame contains no status code, _The WebSocket
Connection Close Code_ is considered to be 1005. If _The WebSocket
Connection is Closed_ and no Close control frame was received by the
endpoint (such as could occur if the underlying transport connection
is lost), _The WebSocket Connection Close Code_ is considered to be
1006.
如5.5.5和7.4中定义,一个关闭控制数据包会包含一个状态码来代表关闭的原因。WebSocket连接的关闭有可能被任何一个终端发起,有可能同时发起。实现了该协议的应用接收到的第一个关闭控制数据包中包含的状态码称之为:The WebSocket Connection Close Code。如果关闭控制数据包不包含状态码,The WebSocket Connection Close Code默认为1005。假如连接被关闭但是终端没有接收到关闭控制数据包(可能发生在底层连接丢失的情况下),The WebSocket Connection Close Code是1006。
NOTE: Two endpoints may not agree on the value of _The WebSocket
Connection Close Code_. As an example, if the remote endpoint sent a
Close frame but the local application has not yet read the data
containing the Close frame from its socket’s receive buffer, and the
local application independently decided to close the connection and
send a Close frame, both endpoints will have sent and received a Close frame and will not send further Close frames. Each endpoint
will see the status code sent by the other end as _The WebSocket
Connection Close Code_. As such, it is possible that the two
endpoints may not agree on the value of _The WebSocket Connection
Close Code_ in the case that both endpoints _Start the WebSocket
Closing Handshake_ independently and at roughly the same time.
注意:两个终端的WebSocket关闭码的值可能不同。例如,一个远程终端发送了关闭数据包,但是本地的应用还没有读取到这个关闭数据包的时候,它也决定关闭这个连接并发送了关闭数据包,两个终端都发送并接收了关闭数据包,将来不会再发送关闭数据包。每个终端将把对方发送的错误码作为WebSocket Connection Close Code。
7.1.6. The WebSocket Connection Close Reason
7.1.6 WebSocket连接关闭原因
As defined in Sections 5.5.1 and 7.4, a Close control frame may
contain a status code indicating a reason for closure, followed by
UTF-8-encoded data, the interpretation of said data being left to the
endpoints and not defined by this protocol. A closing of the
WebSocket connection may be initiated by either endpoint, potentially
simultaneously. _The WebSocket Connection Close Reason_ is defined as
the UTF-8-encoded data following the status code (Section 7.4)
contained in the first Close control frame received by the
application implementing this protocol. If there is no such data in
the Close control frame, _The WebSocket Connection Close Reason_ is
the empty string.
NOTE: Following the same logic as noted in Section 7.1.5, two
endpoints may not agree on _The WebSocket Connection Close Reason_.
像5.5.1和7.4所说的,一个关闭控制数据包可以包含一个状态码标记关闭的原因,在它后面是UTF-8编码的数据,这些数据的解析留给了终端,并没有在协议中定义。WebSocket连接的关闭可以由任何一个终端同时发起。在状态码后面的UTF-8编码的数据是关闭的原因,它在协议的应用接收的第一个关闭控制数据包中。假如关闭控制数据包中没有这样的数据,WebSocket连接关闭的原因是空字符串。
注意:遵从7.1.5中的提到的逻辑,两个终端在WebSocket连接关闭原因上可能不一致。
7.1.7. Fail the WebSocket Connection
Certain algorithms and specifications require an endpoint to _Fail
the WebSocket Connection_. To do so, the client MUST _Close the
WebSocket Connection_, and MAY report the problem to the user (which
would be especially useful for developers) in an appropriate manner.
Similarly, to do so, the server MUST _Close the WebSocket
Connection_, and SHOULD log the problem.
If _The WebSocket Connection is Established_ prior to the point where
the endpoint is required to _Fail the WebSocket Connection_, the
endpoint SHOULD send a Close frame with an appropriate status code
(Section 7.4) before proceeding to _Close the WebSocket Connection_.
An endpoint MAY omit sending a Close frame if it believes the other
side is unlikely to be able to receive and process the Close frame,
due to the nature of the error that led the WebSocket connection to
fail in the first place. An endpoint MUST NOT continue to attempt to
process data (including a responding Close frame) from the remote
endpoint after being instructed to _Fail the WebSocket Connection_.
Except as indicated above or as specified by the application layer
(e.g., a script using the WebSocket API), clients SHOULD NOT close
the connection.
7.1.7 释放WebSocket连接
某些算法和说明书要求终端去释放WebSocket连接。为了这个目的,客户端必须关闭WebSocket连接,并以适当的方式把问题(尤其对开发者非常有用)上报给用户。最简单的方式就是服务端在关闭WebSocket连接的时候,记录问题日志。
假如WebSocket连接建立的时候要求终端释放连接,终端在释放连接之前需要设置一个包含错误码的关闭数据包。假如终端认为对方无法接收并处理关闭数据包,它可能不会发送关闭数据包,由于该错误的自然性(nature)致使它成为WebSocket连接失败的罪魁祸首。一个终端在得到释放WebSocket连接的指示后,不应该再持续从远程终端获取的数据。除去上述定义或应用层特殊定义,客户端不应该关闭连接。
7.2. Abnormal Closures
7.2 异常关闭
7.2.1. Client-Initiated Closure
7.2.1客户端发起关闭
Certain algorithms, in particular during the opening handshake,
require the client to _Fail the WebSocket Connection_. To do so, the
client MUST _Fail the WebSocket Connection_ as defined in
Section 7.1.7.
If at any point the underlying transport layer connection is
unexpectedly lost, the client MUST _Fail the WebSocket Connection_.
Except as indicated above or as specified by the application layer
(e.g., a script using the WebSocket API), clients SHOULD NOT close
the connection.
某些算法,由其是在打开握手时,要求客户端去释放WebSocket连接。为此,客户端必须像7.1.7中定义的释放WebSocket连接。
在任何情况下底层的传输层意外丢失,客户端必须释放WebSocket连接。除去上述定义或应用层特殊定义,客户端不应该关闭连接。
7.2.2. Server-Initiated Closure
Certain algorithms require or recommend that the server _Abort the
WebSocket Connection_ during the opening handshake. To do so, the
server MUST simply _Close the WebSocket Connection_ (Section 7.1.1).
7.2.2 服务端发起关闭
某些算法要求或建议服务端在打开握手时终止WebSocket连接。为此服务端必须简单的关闭WebSocket连接。
7.2.3. Recovering from Abnormal Closure
7.2.3 从异常关闭恢复
Abnormal closures may be caused by any number of reasons. Such
closures could be the result of a transient error, in which case
reconnecting may lead to a good connection and a resumption of normal
operations. Such closures may also be the result of a nontransient
problem, in which case if each deployed client experiences an
abnormal closure and immediately and persistently tries to reconnect,
the server may experience what amounts to a denial-of-service attack
by a large number of clients trying to reconnect. The end result of
such a scenario could be that the service is unable to recover in a
timely manner or recovery is made much more difficult.
异常关闭可能由很多原因引起。在仅仅是临时错误引起的关闭情况下,恢复连接可以获得一个好的连接并使操作恢复正常。这种关闭也可能是非临时错误引起的,这种情况下假如每一个部署的客户端都经历了异常关闭然后立即重新连接,服务端将会由于大量的客户端准备去重新连接而遭受到服务器拒绝服务攻击。这种情景的最终结果是服务端不能及时恢复或者致使恢复过程非常复杂。
To prevent this, clients SHOULD use some form of backoff when trying
to reconnect after abnormal closures as described in this section.
The first reconnect attempt SHOULD be delayed by a random amount of
time. The parameters by which this random delay is chosen are left
to the client to decide; a value chosen randomly between 0 and 5
seconds is a reasonable initial delay though clients MAY choose a
different interval from which to select a delay length based on
implementation experience and particular application.
Should the first reconnect attempt fail, subsequent reconnect
attempts SHOULD be delayed by increasingly longer amounts of time,
using a method such as truncated binary exponential backoff.
为了避免这种情况,客户端在遇到本节说的异常关闭后重新连接时需要某种形式的补偿。第一个重连请求需要有一个随机时间的等待。客户端决定影响随机等待时间的参数;在0到5秒之间随机选择的数字是一个合理的初始值,因此客户端从哪里选一个不同的时间间隔取决于实施经验和特定应用。当第一次重连失败,后续的重连需要等待更长的时间,可以使用类似于二进制指数(truncated binary exponential backoff)的方法。
7.3. Normal Closure of Connections
7.3正常关闭连接
Servers MAY close the WebSocket connection whenever desired. Clients
SHOULD NOT close the WebSocket connection arbitrarily. In either
case, an endpoint initiates a closure by following the procedures to
_Start the WebSocket Closing Handshake_ (Section 7.1.2).
服务端可以在任何期望的时候关闭WebSocket连接。客户端不能强制关闭WebSocket连接。在两种情况下,一个终端按照7.1.2中的步骤启动WebSocket关闭握手而启动关闭。
7.4. Status Codes
7.4 状态码
When closing an established connection (e.g., when sending a Close
frame, after the opening handshake has completed), an endpoint MAY
indicate a reason for closure. The interpretation of this reason by
an endpoint, and the action an endpoint should take given this
reason, are left undefined by this specification. This specification
defines a set of pre-defined status codes and specifies which ranges
may be used by extensions, frameworks, and end applications. The
status code and any associated textual message are optional
components of a Close frame.
当关闭一个连接时(当打开握手已经关闭后发送一个关闭数据包),终端可能提示关闭原因。终端如何解析原因、终端如何给出原因都没有在说明书中定义。该说明书定义了一些状态码并指定了扩展、框架、高端应用的状态码范围。在关闭数据包中状态码以及相关的文本信息都是可选的。
7.4.1. Defined Status Codes
7.4.1 已定义的状态码
Endpoints MAY use the following pre-defined status codes when sending
a Close frame.
当终端发送一个关闭数据包时可能会用到后面定义的状态码。
1000
1000 indicates a normal closure, meaning that the purpose for
which the connection was established has been fulfilled.
1000 代表正常关闭,意思是建立的连接已经完成。
1001
1001 indicates that an endpoint is "going away", such as a server
going down or a browser having navigated away from a page.
1001代表终端要离开,如服务端关机或者浏览器从一个页面离开。
1002
1002 indicates that an endpoint is terminating the connection due
to a protocol error.
1002代表终端由于协议错误终止连接。
1003
1003 indicates that an endpoint is terminating the connection
because it has received a type of data it cannot accept (e.g., an
endpoint that understands only text data MAY send this if it
receives a binary message).
1003代表终端由于无法承担接收的数据而终止连接(例如一个仅接收文本的终端如果接收到了二进制信息会发送这个状态码)。
1004
Reserved. The specific meaning might be defined in the future.
1004保留,可能会在将来定义。
1005
1005 is a reserved value and MUST NOT be set as a status code in a
Close control frame by an endpoint. It is designated for use in
applications expecting a status code to indicate that no status
code was actually present.
1005被保留,不能在终端发送的关闭控制数据包中作为状态码存在。它被设计用在应用中,表示没有状态码实际存在。
1006
1006 is a reserved value and MUST NOT be set as a status code in a
Close control frame by an endpoint. It is designated for use in
applications expecting a status code to indicate that the
connection was closed abnormally, e.g., without sending or
receiving a Close control frame.
1006被保留,不能在终端发送的关闭控制数据包中作为状态码存在。它被设计用在应用中,表示连接异常关闭的状态码,例如没有发送或接收一个关闭控制数据包。
1007
1007 indicates that an endpoint is terminating the connection
because it has received data within a message that was not
consistent with the type of the message (e.g., non-UTF-8 [RFC3629]
data within a text message).
1007代表一个终端由于接收到的消息中的数据与消息类型不匹配而去关闭连接。
1008
1008 indicates that an endpoint is terminating the connection
because it has received a message that violates its policy. This
is a generic status code that can be returned when there is no
other more suitable status code (e.g., 1003 or 1009) or if there
is a need to hide specific details about the policy.
1008代表一个终端由于接收到的消息违反了协议而去停止连接。这个是一般性状态标志,当没有合适的状态码或需要隐藏具体细节的时候可以返回这个状态码。
1009
1009 indicates that an endpoint is terminating the connection
because it has received a message that is too big for it to
process.
1009代表一个终端由于接收到了太大的不能处理的数据,而去停止连接。
1010
1010 indicates that an endpoint (client) is terminating the
connection because it has expected the server to negotiate one or
more extension, but the server didn’t return them in the response
message of the WebSocket handshake. The list of extensions that are needed SHOULD appear in the /reason/ part of the Close frame.
Note that this status code is not used by the server, because it
can fail the WebSocket handshake instead.
1010代表客户端正在停止连接,因为客户端期望服务端支撑一个或多个扩展,但是服务端在WebSocket握手的响应消息中没有包含它们。扩展的列表应该在关闭数据包的reason字段出现。注意这个状态码不能被服务端使用,因为它反而会释放WebSocket握手。
1011
1011 indicates that a server is terminating the connection because
it encountered an unexpected condition that prevented it from
fulfilling the request.
1011代表服务端正在停止连接,原因是它遇到了意料之外的情况不能完成请求。
1015
1015 is a reserved value and MUST NOT be set as a status code in a
Close control frame by an endpoint. It is designated for use in
applications expecting a status code to indicate that the
connection was closed due to a failure to perform a TLS handshake
(e.g., the server certificate can’t be verified).
1015被保留,不能在终端发送的关闭控制数据包中作为状态码存在。它被设计用在应用中,代表连接是在进行TLS握手时失败而造成的关闭。
7.4.2. Reserved Status Code Ranges
7.4.2 保留状态码的范围
0-999
Status codes in the range 0-999 are not used.
0-999
0-999的状态码没有使用。
1000-2999
Status codes in the range 1000-2999 are reserved for definition by
this protocol, its future revisions, and extensions specified in a
permanent and readily available public specification.
1000-2999
1000-2999的状态码预留给协议定义使用,未来的修订、长久的扩展、现成的规范。
3000-3999
Status codes in the range 3000-3999 are reserved for use by
libraries, frameworks, and applications. These status codes are
registered directly with IANA. The interpretation of these codes
is undefined by this protocol.
3000-3999
3000-3999的状态码预留给函数库、框架和应用程序。这些代码被IANA直接注册。这些编码的解析不在这个协议中定义。
4000-4999
Status codes in the range 4000-4999 are reserved for private use
and thus can’t be registered. Such codes can be used by prior
agreements between WebSocket applications. The interpretation of
these codes is undefined by this protocol.
4000-4999的状态码是为了私用而预留的,不能重新注册。这种编码可以优先用在多个WebSocket应用中。这些编码的解析不在这个协议中定义。
8. Error Handling
8.1. Handling Errors in UTF-8-Encoded Data
When an endpoint is to interpret a byte stream as UTF-8 but finds
that the byte stream is not, in fact, a valid UTF-8 stream, that
endpoint MUST _Fail the WebSocket Connection_. This rule applies
both during the opening handshake and during subsequent data
exchange.
8.错误处理
8.1 使用UTF-8编码数据处理错误
假如终端打算解析一个UTF-8编码的二进制流,但是发现字节流不是合法的UTF-8流,终端会立即释放WebSocket连接。这个规则同时适用于打开握手以及数据交互的过程。