WebSocket:从建立连接到关闭的完整流程
WebSocket完整流程详解
WebSocket是一种基于TCP的全双工通信协议,允许客户端和服务器之间建立持久的双向连接,实现实时数据传输。本文将详细介绍WebSocket的完整流程,包括建立连接、数据传输和关闭连接等步骤,并对每个环节进行深入解析。
一、WebSocket连接的建立
1. 客户端发起握手请求
客户端通过HTTP协议向服务器发送握手请求,意图将协议从HTTP升级为WebSocket。在这个请求中,包含了一些特殊的头部信息,以表明希望进行协议升级。
HTTP请求示例:
GET /chat HTTP/1.1
Host: example.com:80
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13
解释:
GET /chat HTTP/1.1
:请求服务器的/chat
路径,使用HTTP/1.1协议。Host: example.com:80
:指定请求的主机名和端口号。Upgrade: websocket
:表示希望将协议升级为WebSocket。Connection: Upgrade
:表示此次连接请求是一个协议升级请求。Sec-WebSocket-Key
:客户端随机生成的Base64编码的密钥,用于安全校验。Sec-WebSocket-Version
:WebSocket协议的版本号,当前常用版本为13。
2. 服务器验证并处理协议升级
服务器接收到握手请求后,首先对请求头进行验证,确认请求符合WebSocket协议的要求。如果验证通过,服务器将准备响应以完成协议升级。
服务器需验证的要点:
- 检查
Upgrade
头部是否为websocket
。 - 检查
Connection
头部是否包含Upgrade
。 - 验证
Sec-WebSocket-Key
是否存在且格式正确。 - 确认
Sec-WebSocket-Version
是否支持。
3. 服务器返回握手响应
服务器生成握手响应,包含必要的头部信息,状态码为 101 Switching Protocols
,表示协议升级成功。
HTTP响应示例:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
解释:
HTTP/1.1 101 Switching Protocols
:状态码101,表示协议切换。Upgrade: websocket
:确认升级为WebSocket协议。Connection: Upgrade
:确认此次连接为协议升级。Sec-WebSocket-Accept
:服务器根据客户端的Sec-WebSocket-Key
计算得到的校验值。
校验值计算过程:
服务器从请求头的 Sec-WebSocket-Key
获取密钥,拼接上一个固定的GUID(258EAFA5-E914-47DA-95CA-C5AB0DC85B11
),然后通过SHA-1哈希和Base64编码生成 Sec-WebSocket-Accept
。
代码示例(伪代码):
function generateAcceptValue(secWebSocketKey) {
const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
const hash = sha1(secWebSocketKey + GUID);
const acceptValue = base64Encode(hash);
return acceptValue;
}
解释:
secWebSocketKey
:客户端提供的密钥。GUID
:固定的GUID字符串。sha1()
:对拼接后的字符串进行SHA-1哈希计算。base64Encode()
:将哈希结果进行Base64编码,得到Sec-WebSocket-Accept
。
4. 连接建立完成
当客户端接收到服务器的握手响应,并验证 Sec-WebSocket-Accept
的值正确后,WebSocket连接正式建立。此时,客户端和服务器之间的TCP连接已从HTTP升级为WebSocket协议,双方可以开始双向通信。
二、数据传输
1. 消息格式
WebSocket的数据帧具有特定的格式,用于传输文本或二进制数据。每个数据帧包含帧头和负载数据。
数据帧基本结构:
- FIN:1位,表示是否为消息的最后一个分片。
- Opcode:4位,定义了负载数据的解释方式(如文本数据、二进制数据、关闭连接等)。
- Mask:1位,表示是否对负载数据进行了掩码处理(客户端发送的消息必须掩码)。
- Payload Length:7位或7+16位或7+64位,表示负载数据的长度。
- Masking-Key:32位,当Mask为1时存在,用于解码负载数据。
- Payload Data:实际传输的数据。
2. 客户端发送消息
客户端可以使用WebSocket的 send()
方法发送数据。
示例:
// 在浏览器环境中
const socket = new WebSocket('ws://example.com/chat');
socket.onopen = function() {
socket.send('Hello, Server!');
};
解释:
new WebSocket('ws://example.com/chat')
:创建一个指向服务器的WebSocket连接。socket.onopen
:当连接建立后,触发onopen
事件。socket.send()
:通过连接发送字符串'Hello, Server!'
。
3. 服务器接收并响应消息
服务器接收到客户端的消息后,可以进行处理并发送响应。
示例(Node.js环境):
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });
server.on('connection', function(socket) {
socket.on('message', function(message) {
console.log('Received from client:', message);
socket.send('Hello, Client!');
});
});