标题:
WebSocket 协议(7)
[打印本页]
作者:
look_w
时间:
2019-1-15 19:47
标题:
WebSocket 协议(7)
4.2.2 发送服务端的握手响应当客户端对服务端建立了一个 WebSocket 连接之后,服务端必须完成接下来的步骤,以此去接受客户端的连接,并回应客户端的握手。
如果连接发生在 HTTPS(基于 TLS 的 HTTP)端口上,那么要执行一个 TLS 握手。如果 TLS 握手失败,就必须关闭连接;否则的话之后的所有通信都必须建立在加密隧道上。
服务端可以对客户端执行另外的授权认证,比如通过返回 401 状态码和 对应的 |WWW-Authenticate|,相关描述在
服务端也可以对客户端进行重定向,使用 3xx 状态码 。注意这一步也可以发生在上一步之前。
确认下面的信息:
[url=]
[/url]
/origin/
客户端握手请求中的
|origin| 头字段表明了脚本在发起请求时所处的源。源被序列化成 ASCII 并且被转换成了小写。服务端可以选择性地使用这个信息去决定是否接受这个连接请求。如果服务端不验证源的话,那么它将接收来自任何地方的请求。
如果服务端不想接收这个连接的话,它必须返回适当的 HTTP 错误状态码(比如
403
Forbidden)并且终止接下来的 WebSocket 握手过程。更详细的内容,见第
10
节
/key/
客户端握手请求中的
|Sec-WebSocket-Key| 头字段包含了一个使用 base64 编码后的值,如果解码的话,这个值是
16
字节长的。这个编码后的值用于服务端生成表示其接收客户端请求的内容。服务端没有必要去将这个值进行解码。
/version/
客户端握手请求中的
|Sec-WebSocket-Version| 头字段包含了客户端希望进行通信的 WebSocket 协议的版本号。如果服务端不能理解这个版本号的话,那么它必须终止接下来的握手过程,并给客户端返回一个适当的 HTTP 错误状态码
(比如
426
Upgrade Required),同时在返回的信息中包含一个 |Sec-WebSocket-Version|
头字段,通过其值指明服务端能够理解的协议版本号。
/subprotocol/
服务端可以选择接受其中一个子协议,或者
null
。子协议的选取必须来自客户端的握手信息中的 |Sec-WebSocket-Protocol| 头字段的元素集合。如果客户端没有发送 |Sec-WebSocket-Protocol| 头字段,或者客户端发送的 |Sec-WebSocket-Protocol|
头字段中没有一个可以被当前服务端接受的话,服务端唯一可以返回值就是
null
。不发送这个头字段就表示其值是
null
。注意,空字符串并不表示这里的
null
并且根据 RFC2616 中的 ABNF 定义,空字符串也是不合法的。根据协议中的描述,客户端握手请求中的
|Sec-WebSocket-Protocol|
是一个可选的头字段,所以如果服务端必须使用这个头字段的话,可以选择性的拒绝客户端的连接请求。
/extensions/
一个可以为空的列表,表示客户端希望使用的协议级别的扩展。如果服务端支持多个扩展,那么必须从客户端握手请求中的
|Sec-WebSocket-Extensions| 按需选择多个其支持的扩展。如果客户端没有发送次头字段,则表示这个字段的值是
null
,
空字符并不表示
null
。返回的 |Sec-WebSocket-Extensions| 值中不可以包含客户端不支持的扩展。这个字段值的选择和解释将在第
9
节中讨论[url=]
[/url]
如果服务端选择接受来自客户端的连接,它必须回答一个有效的 HTTP 响应:
[url=]
[/url]
一个状态行,包含了响应码
101
。比如 HTTP/
1.1
101
Switching Protocols一个
|Upgrade|
头字段,值为 websocket一个
|Connection|
头字段,值为 Upgrade一个
|Sec-WebSocket-Accept| 头字段。这个值通过连接定义在
4.2
.
2
节中的第
4
步的 /key/ 和字符串 258EAFA5-E914-47DA-95CA-C5AB0DC85B11,连接后的字符串运用 SHA-
1
得到一个
20
字节的值,
最后使用 base64 将这
20
个字节的内容编码,得到最后的用于返回的字符串。相应的 ABNF 定义如下:Sec
-WebSocket-Accept = base64-value-non-
emptybase64
-value-non-empty = (
1
*base64-data [ base64-padding ]) |
base64
-
paddingbase64
-data = 4base64-
characterbase64
-padding = (2base64-character
"
==
"
) |
(3base64
-character
"
=
"
)base64
-character = ALPHA | DIGIT |
"
+
"
|
"
/
"
注意:作为一个例子,如果来自客户端握手请求中的
|Sec-WebSocket-Key| 的值是 dGhlIHNhbXBsZSBub25jZQ== 的话,那么服务端需要将 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 字符串追加到其后,
变成 dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11,再对这个连接后的字符串运用 SHA-
1
哈希得到这些内容
0xb3
0x7a
0x4f
0x2c
0xc0
0x62
0x4f
0x16
0x90
0xf6
0x46
0x06
0xcf
0x38
0x59
0x45
0xb2
0xbe
0xc4
0xea
,对于哈希后的内容进行 base64 编码,最后得到 s3pPLMBiTxaQ9kYGzzhZRbK+xOo=,
然后将这个值作为服务端返回的头字段 |Sec-WebSocket-Accept|
的字段值。可选的,一个
|Sec-WebSocket-Protocol| 头字段,它的值已经在第
4.2
.
2
节中的第
4
步定义了可选的,一个
|Sec-WebSocket-Extensions| 头字段,它的值已经在第4.
2.2
节中的第
4
步定义了。如果有服务端选择了多个扩展,可以将它们分别放在 |Sec-WebSocket-Extensions| 头字段中,或者合并到一起放到一个
|Sec-WebSocket-Extensions| 头字段中。[url=]
[/url]
这样就完成了服务端的握手。如果服务端没有发生终止的完成了所有的握手步骤,那么服务端就可以认为连接已经建立了,并且 WebSocket 连接的状态变为 OPEN。在这时,客户端和服务端就可以开始发送(或者接收)数据了。
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0