.NET Core 2 TcpListener服务器无法与HTML5 WebSocket客户端完成握手
解决.NET Core 2 TcpListener与HTML5 WebSocket握手问题
嘿,这个问题我之前做自定义Socket服务时也踩过坑!你猜得没错——TcpListener是纯粹的底层TCP监听组件,完全没有内置WebSocket的握手协议处理逻辑,这就是为什么你的.NET TCP客户端能正常连接,但HTML5 WebSocket一直卡在connecting状态、触发不了onopen的核心原因。
要让WebSocket客户端成功握手,你必须手动实现WebSocket的HTTP握手流程,具体步骤如下:
1. 解析客户端的握手请求
WebSocket的握手始于客户端发送一个HTTP GET请求,其中包含关键的Sec-WebSocket-Key头。你需要从TCP流中读取这个请求,并提取出该字段的值。
示例代码片段(读取请求并解析Key):
using (var client = listener.AcceptTcpClient()) using (var stream = client.GetStream()) { // 读取客户端的HTTP握手请求 byte[] buffer = new byte[1024]; int bytesRead = stream.Read(buffer, 0, buffer.Length); string request = Encoding.UTF8.GetString(buffer, 0, bytesRead); // 提取Sec-WebSocket-Key string webSocketKey = null; foreach (var line in request.Split('\n')) { if (line.StartsWith("Sec-WebSocket-Key:")) { webSocketKey = line.Split(':')[1].Trim(); break; } } if (string.IsNullOrEmpty(webSocketKey)) { // 不是合法的WebSocket握手请求,断开连接 client.Close(); continue; } // 后续握手逻辑... }
2. 计算握手响应的哈希值
根据WebSocket协议规范,你需要将提取到的Sec-WebSocket-Key与固定字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11拼接,然后对拼接后的字符串做SHA-1哈希,再将哈希结果做Base64编码,得到Sec-WebSocket-Accept的值。
计算代码:
string acceptKey = webSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; byte[] acceptKeyBytes = Encoding.UTF8.GetBytes(acceptKey); byte[] hashBytes = SHA1.Create().ComputeHash(acceptKeyBytes); string acceptValue = Convert.ToBase64String(hashBytes);
3. 构造并返回握手响应
接下来需要向客户端返回符合HTTP规范的响应,必须包含以下几个关键响应头:
Upgrade: websocketConnection: UpgradeSec-WebSocket-Accept: [计算出的acceptValue]
构造并发送响应的代码:
string response = $"HTTP/1.1 101 Switching Protocols\r\n" + $"Upgrade: websocket\r\n" + $"Connection: Upgrade\r\n" + $"Sec-WebSocket-Accept: {acceptValue}\r\n\r\n"; byte[] responseBytes = Encoding.UTF8.GetBytes(response); stream.Write(responseBytes, 0, responseBytes.Length); stream.Flush();
额外注意事项
- 完成握手后,后续的WebSocket通信需要按照WebSocket帧格式来处理(比如数据帧的掩码、opcode解析等),如果只是简单的文本通信,你还需要手动实现帧的打包和解包逻辑。
- 如果你不需要底层TCP的自定义逻辑,其实更推荐使用ASP.NET Core内置的WebSocket中间件,它已经封装好了握手和帧处理,开发效率会高很多。
内容的提问来源于stack exchange,提问作者David Horáček




