C#WebSocket服务端处理多客户端连接
优化 WebSocket 服务端代码
源码
using System.Text; // 用于发送和接收信息时处理文本
using System.Net; // 用于处理网络连接
using System.Net.WebSockets; // 用于处理WebSocket连接
namespace Test.Program
{
static class Program
{
static HttpListener listener;
static void Main(string[] args)
{
const string HOST = "localhost"; // 监听的主机名
const int PORT = 3030; // 监听的端口号
listener = new HttpListener(); // 实例化HttpListener
listener.Prefixes.Add($"http://{HOST}:{PORT}/"); // 设置监听的URL
listener.Start(); // 开始监听
ListenClientConnections()
.Wait();
}
async static Task ListenClientConnections()
{
while (true)
{
// 等待客户端的连接
Console.WriteLine("等待客户端连接");
HttpListenerContext context = await listener.GetContextAsync();
// 判断此连接是否为WebSocket的请求
if (context.Request.IsWebSocketRequest)
{
Console.WriteLine($"接收到客户端连接");
// 这时候,我们可以用WebSocket来接受客户端的连接
WebSocket webSocket = context.AcceptWebSocketAsync(null).Result.WebSocket;
// 这时候我们可以根据需要来处理客户端的消息
while (webSocket.State == WebSocketState.Open)
{
// 等待客户端的消息
byte[] buffer = new byte[1024]; // 定义一个缓冲区大小为1KB
ArraySegment<byte> segment = new ArraySegment<byte>(buffer); // 定义一个数组段
CancellationToken cancellationToken = CancellationToken.None; // 定义一个取消标记
// 这时候这里一直等待客户端的消息
Console.WriteLine("等待客户端消息");
WebSocketReceiveResult result = await webSocket.ReceiveAsync(segment, cancellationToken);
// 文本类型的消息
if (result.MessageType == WebSocketMessageType.Text)
{
// 这里可以对客户端的消息进行处理
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
// 给客户端发送消息
string responseMessage = $"接收到客户端的消息: {message}";
Console.WriteLine(responseMessage);
byte[] responseBuffer = Encoding.UTF8.GetBytes(responseMessage);
await webSocket.SendAsync(
responseBuffer, // 发送的消息,字节数组类型
WebSocketMessageType.Text, // 消息类型为文本
true, // 最后一帧,如果为false,则表示后面还有数据
CancellationToken.None // 取消标记
);
}
}
Console.WriteLine("客户端连接断开");
}
}
}
}
}
在这个源码中,我发现,这段代码只支持处理一个客户端的连接,如果有多个客户端连接,那么只有第一个客户端连接会被处理。
为了支持多个客户端连接,我们需要修改代码,使得 WebSocket 服务端可以同时处理多个客户端的连接。
1. 重构 ListenClientConnections 方法
只要将等待客户端连接的部分、等待客户端消息的部分、处理消息的部分、发送消息的部分都提取出来,封装成新的方法即可
- 创建 ListenClientConnection 方法,用于监听客户端连接,并返回 WebSocket 对象。
- 创建 WebSocketHandler 方法,用于处理 WebSocket 连接,包括接收消息、处理消息、发送消息。
- 创建 HandleMessage 方法,用于处理客户端的消息、处理业务逻辑。
- 修改 ListenClientConnections 方法,用于监听客户端连接,并创建 WebSocketHandler 任务。
为了跟踪客户端连接的数量,我们可以在全局变量中定义一个 clientCount 变量。
static int clientCount = 0;
1. 创建 ListenClientConnection 方法
用于监听客户端连接,并返回 WebSocket 对象。
private static async Task<WebSocket> ListenClientConnection()
{
while (true)
{
HttpListenerContext context = await listener.GetContextAsync();
// 判断此连接是否为WebSocket的请求
if (context.Request.IsWebSocketRequest)
{
// 这时候,我们可以用WebSocket来接受客户端的连接
WebSocket webSocket = context.AcceptWebSocketAsync(null).Result.WebSocket;
// 这里我们需要把连接对象返回
return webSocket;
}
}
}
2. 创建 WebSocketHandler 方法
用于处理 WebSocket 连接,包括接收消息、处理消息、发送消息。
private static async Task WebSocketHandler(WebSocket webSocket)
{
while (webSocket.State == WebSocketState.Open)
{
// 等待客户端的消息
byte[] buffer = new byte[1024]; // 定义一个缓冲区大小为1KB
ArraySegment<byte> segment = new ArraySegment<byte>(buffer); // 定义一个数组段
CancellationToken cancellationToken = CancellationToken.None; // 定义一个取消标记
// 这时候这里一直等待客户端的消息
WebSocketReceiveResult result = await webSocket.ReceiveAsync(segment, cancellationToken);
// 文本类型的消息
if (result.MessageType == WebSocketMessageType.Text)
{
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
await HandleMessage(webSocket, message); // 调用处理消息的方法
}
}
Console.WriteLine("客户端连接断开");
clientCount--; // 连接数量减一
// 输出服务端状态
Console.WriteLine("接收到客户端连接");
Console.WriteLine("---服务器状态begin---");
Console.WriteLine($"连接数量: {clientCount}");
Console.WriteLine("---服务器状态end---");
}
3. 创建 HandleMessage 方法
用于处理客户端的消息、处理业务逻辑。
private static async Task HandleMessage(WebSocket webSocket, string message)
{
Console.WriteLine($"接收到客户端的消息: {message}");
if (message.StartsWith("CLOSE"))
{
listener.Close();
}
// 这里可以对客户端的消息进行处理
// 给客户端发送消息
string responseMessage = $"返回给客户端消息: {message}";
Console.WriteLine(responseMessage);
byte[] responseBuffer = Encoding.UTF8.GetBytes(responseMessage);
await webSocket.SendAsync(
responseBuffer, // 发送的消息,字节数组类型
WebSocketMessageType.Text, // 消息类型为文本
true, // 最后一帧,如果为false,则表示后面还有数据
CancellationToken.None // 取消标记
);
}
4. 修改 ListenClientConnections 方法
用于监听客户端连接,并创建 WebSocketHandler 任务。
async static Task async static Task ListenClientConnections()
{
while (listener.IsListening)
{
Console.WriteLine("等待客户端连接");
WebSocket webSocket = await ListenClientConnection();
clientCount++; // 连接数量加一
// 输出服务端状态
Console.WriteLine("接收到客户端连接");
Console.WriteLine("---服务器状态begin---");
Console.WriteLine($"连接数量: {clientCount}");
Console.WriteLine("---服务器状态end---");
WebSocketHandler(webSocket);
}
}
2. 完整代码
using System.Text; // 用于发送和接收信息时处理文本
using System.Net; // 用于处理网络连接
using System.Net.WebSockets; // 用于处理WebSocket连接
namespace Test.Program
{
static class Program
{
static HttpListener listener;
static int clientCount = 0;
static void Main(string[] args)
{
const string HOST = "localhost"; // 监听的主机名
const int PORT = 3030; // 监听的端口号
listener = new HttpListener(); // 实例化HttpListener
listener.Prefixes.Add($"http://{HOST}:{PORT}/"); // 设置监听的URL
listener.Start(); // 开始监听
ListenClientConnections()
.Wait();
}
private static async Task<WebSocket> ListenClientConnection()
{
while (true)
{
HttpListenerContext context = await listener.GetContextAsync();
// 判断此连接是否为WebSocket的请求
if (context.Request.IsWebSocketRequest)
{
// 这时候,我们可以用WebSocket来接受客户端的连接
WebSocket webSocket = context.AcceptWebSocketAsync(null).Result.WebSocket;
// 这里我们需要把连接对象返回
return webSocket;
}
}
}
private static async Task WebSocketHandler(WebSocket webSocket)
{
while (webSocket.State == WebSocketState.Open)
{
// 等待客户端的消息
byte[] buffer = new byte[1024]; // 定义一个缓冲区大小为1KB
ArraySegment<byte> segment = new ArraySegment<byte>(buffer); // 定义一个数组段
CancellationToken cancellationToken = CancellationToken.None; // 定义一个取消标记
// 这时候这里一直等待客户端的消息
WebSocketReceiveResult result = await webSocket.ReceiveAsync(segment, cancellationToken);
// 文本类型的消息
if (result.MessageType == WebSocketMessageType.Text)
{
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
await HandleMessage(webSocket, message); // 调用处理消息的方法
}
}
Console.WriteLine("客户端连接断开");
clientCount--;
// 输出服务端状态
Console.WriteLine("接收到客户端连接");
Console.WriteLine("---服务器状态begin---");
Console.WriteLine($"连接数量: {clientCount}");
Console.WriteLine("---服务器状态end---");
}
private static async Task HandleMessage(WebSocket webSocket, string message)
{
Console.WriteLine($"接收到客户端的消息: {message}");
if (message.StartsWith("CLOSE"))
{
listener.Close();
}
// 这里可以对客户端的消息进行处理
// 给客户端发送消息
string responseMessage = $"返回给客户端消息: {message}";
Console.WriteLine(responseMessage);
byte[] responseBuffer = Encoding.UTF8.GetBytes(responseMessage);
await webSocket.SendAsync(
responseBuffer, // 发送的消息,字节数组类型
WebSocketMessageType.Text, // 消息类型为文本
true, // 最后一帧,如果为false,则表示后面还有数据
CancellationToken.None // 取消标记
);
}
async static Task ListenClientConnections()
{
while (listener.IsListening)
{
Console.WriteLine("等待客户端连接");
WebSocket webSocket = await ListenClientConnection();
clientCount++;
// 输出服务端状态
Console.WriteLine("接收到客户端连接");
Console.WriteLine("---服务器状态begin---");
Console.WriteLine($"连接数量: {clientCount}");
Console.WriteLine("---服务器状态end---");
WebSocketHandler(webSocket);
}
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!