WebSocket 快速入门教程(附示例源码)
WebSocket 是什么?
WebSocket 是一种在单个 TCP 连接上提供全双工通信的协议,由 IETF 标准化为 RFC 6455。它设计用于 Web 浏览器和服务器之间的实时数据交换,但也适用于任何客户端-服务器场景。
简单类比:
HTTP 就像写信:你写好信寄出去,对方收到后回信,你才能收到回复。每次通信都需要重新“寄信”。
WebSocket 就像打电话:双方先拨通电话(建立连接),之后任何一方都可以随时说话,另一方随时收听,直到挂断电话(关闭连接)。
WebSocket 使用 ws:// 或 wss:// 作为协议前缀(wss 是加密版本,类似 HTTPS)。
- 为什么需要 WebSocket?
传统 HTTP 在实时场景下面临三大痛点:
痛点 说明
单向请求 只有客户端能发起请求,服务器无法主动推送
短连接 每次请求都需要重新建立 TCP 连接(三次握手),开销大
实时性差 轮询(Polling)需要频繁发起请求,浪费带宽且延迟不可控
常见的“伪实时”方案:
短轮询:客户端每隔几秒就发一次请求,询问是否有新数据。缺点:大量无效请求,浪费资源。
长轮询:客户端发起请求后,服务器保持连接打开,直到有数据或超时才返回。缺点:占用连接资源,实现复杂。
WebSocket 通过一次握手建立持久连接,后续所有数据都通过该连接传输,帧头仅 2 字节,通信效率极高,延迟达到毫秒级。因此,它已成为实时 Web 应用的事实标准。
- WebSocket 工作原理
WebSocket 通信分为两个阶段:握手阶段和数据传输阶段。
4.1 握手阶段
握手使用 HTTP 协议,客户端发送一个特殊的 GET 请求,包含 Upgrade: websocket 头,表明希望将协议升级为 WebSocket。服务器如果支持,则返回状态码 101 Switching Protocols,协议切换完成。此后,该 TCP 连接就不再是 HTTP 协议,而是 WebSocket 协议。
示例请求头:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
响应头:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
4.2 数据传输阶段
握手成功后,连接进入全双工模式。双方可以随时发送数据帧,帧格式轻量,支持文本(UTF-8)和二进制数据。通信保持持久,直到一方主动关闭连接或网络中断。
- 前端 WebSocket API 及示例
浏览器原生提供了 WebSocket 对象,无需第三方库。
5.1 核心 API
// 创建连接
const socket = new WebSocket(‘ws://localhost:8080’);
// 事件监听
socket.onopen = function() { /* 连接建立 / };
socket.onmessage = function(event) { / 收到消息,event.data 为数据 / };
socket.onerror = function(error) { / 出错 / };
socket.onclose = function() { / 连接关闭 */ };
// 发送数据
socket.send(‘Hello Server!’);
// 关闭连接
socket.close();
5.2 完整前端示例
下面是一个简单的聊天界面 HTML,与任何 WebSocket 服务端兼容。
WebSocket 聊天
发送 断开<script>
// 1. 创建连接(根据实际后端地址修改)
const socket = new WebSocket('ws://localhost:8080/ws');
// 2. 连接成功
socket.onopen = function() {
appendMessage('系统', '✅ 连接已建立', 'system');
};
// 3. 收到消息
socket.onmessage = function(event) {
appendMessage('服务器', event.data, 'server');
};
// 4. 错误处理
socket.onerror = function(error) {
console.error('WebSocket 错误:', error);
appendMessage('系统', '❌ 发生错误', 'system');
};
// 5. 连接关闭
socket.onclose = function() {
appendMessage('系统', '🔌 连接已关闭', 'system');
};
// 6. 发送消息
function sendMessage() {
const input = document.getElementById('input');
const text = input.value.trim();
if (text === '') return;
if (socket.readyState === WebSocket.OPEN) {
socket.send(text);
appendMessage('我', text, 'self');
input.value = '';
} else {
alert('连接未打开');
}
}
// 7. 关闭连接
function closeConnection() {
socket.close();
}
// 辅助:在界面中追加消息
function appendMessage(sender, text, type) {
const output = document.getElementById('output');
const div = document.createElement('div');
div.className = 'msg ' + (type || '');
div.textContent = `[${sender}] ${text}`;
output.appendChild(div);
output.scrollTop = output.scrollHeight;
}
// 回车发送
document.getElementById('input').addEventListener('keyup', function(e) {
if (e.key === 'Enter') sendMessage();
});
</script>
6. C# 后端 WebSocket 服务端实现 在 C# 中,我们有多种方式搭建 WebSocket 服务,下面分别介绍 ASP.NET Core 原生、轻量级 Fleck 和 HttpListener 自托管 三种方案,你可以根据项目需求选择。
6.1 方案一:ASP.NET Core 原生 WebSocket(推荐)
适用于 .NET Core / .NET 5+ 的 Web 应用程序,与 MVC/WebAPI 无缝集成。
步骤:
创建一个空的 ASP.NET Core Web 项目。
在 Program.cs 中启用 WebSocket 中间件并定义 /ws 路由。
using System.Collections.Concurrent;
using System.Net.WebSockets;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 配置 WebSocket
app.UseWebSockets(new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromSeconds(30),
ReceiveBufferSize = 4 * 1024
});
// 存储所有活跃连接(线程安全)
var connections = new ConcurrentDictionary<string, WebSocket>();
app.Map(“/ws”, async context =>
{
if (context.WebSockets.IsWebSocketRequest)
{
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
var clientId = Guid.NewGuid().ToString();
connections.TryAdd(clientId, webSocket);
Console.WriteLine($“✅ 客户端 {clientId} 已连接”);
await HandleWebSocket(webSocket, clientId, connections);
}
else
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
}
});
app.Run();
// 处理单个 WebSocket 连接
static async Task HandleWebSocket(
WebSocket ws,
string clientId,
ConcurrentDictionary<string, WebSocket> connections)
{
var buffer = new byte[1024 * 4];
WebSocketReceiveResult result;
while (ws.State == WebSocketState.Open)
{
try
{
result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Text)
{
var receivedText = Encoding.UTF8.GetString(buffer, 0, result.Count);
Console.WriteLine($"📩 来自 {clientId}: {receivedText}");
// 回显消息
var reply = $"服务器回显: {receivedText}";
var replyBytes = Encoding.UTF8.GetBytes(reply);
await ws.SendAsync(
new ArraySegment<byte>(replyBytes),
WebSocketMessageType.Text,
true,
CancellationToken.None);
// 如果需要广播,可以调用 Broadcast 方法(见下文)
// await Broadcast($"{clientId}: {receivedText}", connections);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "正常关闭", CancellationToken.None);
}
}
catch (WebSocketException)
{
// 处理异常,如连接突然断开
break;
}
}
// 移除断开的连接
connections.TryRemove(clientId, out _);
Console.WriteLine($"🔌 客户端 {clientId} 已断开");
}
// 广播方法(可选)
static async Task Broadcast(string message, ConcurrentDictionary<string, WebSocket> connections)
{
var bytes = Encoding.UTF8.GetBytes(message);
var tasks = connections.Values
.Where(ws => ws.State == WebSocketState.Open)
.Select(ws => ws.SendAsync(
new ArraySegment(bytes),
WebSocketMessageType.Text,
true,
CancellationToken.None));
await Task.WhenAll(tasks);
}
启动:运行项目,服务端监听在 ws://localhost:5000/ws(默认端口)。
更多推荐



所有评论(0)