C# 实现websocket经典案例

WebSocketDemo/
├── WebSocketServer/      # 服务端项目
│   ├── Program.cs        # 主程序
│   ├── WebSocketServer.cs # WebSocket 服务实现
│   └── WebSocketServer.csproj
└── WebSocketClient/      # 客户端项目
    ├── Program.cs        # 客户端主程序
    ├── WebSocketClient.cs # WebSocket 客户端实现
    └── WebSocketClient.csproj
  1. 创建 WebSocket 服务端
using System.Net.WebSockets;
using System.Text;

public class WebSocketServer
{
    private readonly ILogger<WebSocketServer> _logger;
    private readonly List<WebSocket> _sockets = new();

    public WebSocketServer(ILogger<WebSocketServer> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 处理 WebSocket 连接
    /// </summary>
    public async Task HandleWebSocketAsync(HttpContext context)
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
            _sockets.Add(webSocket);
            _logger.LogInformation("WebSocket 连接已建立");

            await EchoAsync(webSocket);
            
            _sockets.Remove(webSocket);
            _logger.LogInformation("WebSocket 连接已关闭");
        }
        else
        {
            context.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }

    /// <summary>
    /// 广播消息给所有连接的客户端
    /// </summary>
    public async Task BroadcastAsync(string message)
    {
        var buffer = Encoding.UTF8.GetBytes(message);
        var segment = new ArraySegment<byte>(buffer);

        foreach (var socket in _sockets)
        {
            if (socket.State == WebSocketState.Open)
            {
                await socket.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None);
            }
        }
    }

    /// <summary>
    /// 处理单个 WebSocket 连接的消息循环
    /// </summary>
    private async Task EchoAsync(WebSocket webSocket)
    {
        var buffer = new byte[1024 * 4]; // 4KB 缓冲区
        var receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

        while (!receiveResult.CloseStatus.HasValue)
        {
            // 处理接收到的消息
            var message = Encoding.UTF8.GetString(buffer, 0, receiveResult.Count);
            _logger.LogInformation($"收到消息: {message}");

            // 可以在这里添加业务逻辑处理
            var response = $"服务器已收到: {message}";
            var responseBuffer = Encoding.UTF8.GetBytes(response);
            
            // 发送响应
            await webSocket.SendAsync(
                new ArraySegment<byte>(responseBuffer),
                WebSocketMessageType.Text,
                receiveResult.EndOfMessage,
                CancellationToken.None);

            // 继续接收下一条消息
            receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        }

        // 关闭连接
        await webSocket.CloseAsync(
            receiveResult.CloseStatus.Value,
            receiveResult.CloseStatusDescription,
            CancellationToken.None);
    }
}
  1. 在 ASP.NET Core 中配置 WebSocket 中间件
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<WebSocketServer>();
builder.Services.AddLogging();

var app = builder.Build();

// 启用 WebSocket 支持
app.UseWebSockets();

// 配置 WebSocket 路由
app.Map("/ws", async context =>
{
    var webSocketServer = context.RequestServices.GetRequiredService<WebSocketServer>();
    await webSocketServer.HandleWebSocketAsync(context);
});

// 添加一个测试端点用于触发广播
app.MapGet("/broadcast", async (string message, WebSocketServer server) =>
{
    await server.BroadcastAsync(message);
    return $"已广播消息: {message}";
});

app.Run();

客户端实现

using System.Net.WebSockets;
using System.Text;

public class WebSocketClient
{
    private readonly string _uri;
    private ClientWebSocket _webSocket = new();

    public WebSocketClient(string uri)
    {
        _uri = uri;
    }

    /// <summary>
    /// 连接到 WebSocket 服务器
    /// </summary>
    public async Task ConnectAsync()
    {
        await _webSocket.ConnectAsync(new Uri(_uri), CancellationToken.None);
        Console.WriteLine("已连接到 WebSocket 服务器");

        // 启动接收消息的任务
        _ = Task.Run(ReceiveMessagesAsync);
    }

    /// <summary>
    /// 发送消息到服务器
    /// </summary>
    public async Task SendAsync(string message)
    {
        var buffer = Encoding.UTF8.GetBytes(message);
        await _webSocket.SendAsync(
            new ArraySegment<byte>(buffer),
            WebSocketMessageType.Text,
            true,
            CancellationToken.None);
    }

    /// <summary>
    /// 接收服务器消息
    /// </summary>
    private async Task ReceiveMessagesAsync()
    {
        var buffer = new byte[1024 * 4]; // 4KB 缓冲区

        while (_webSocket.State == WebSocketState.Open)
        {
            var result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            
            if (result.MessageType == WebSocketMessageType.Close)
            {
                await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
                Console.WriteLine("WebSocket 连接已关闭");
                break;
            }

            var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
            Console.WriteLine($"收到服务器消息: {message}");
        }
    }

    /// <summary>
    /// 关闭连接
    /// </summary>
    public async Task CloseAsync()
    {
        if (_webSocket.State == WebSocketState.Open)
        {
            await _webSocket.CloseAsync(
                WebSocketCloseStatus.NormalClosure,
                "客户端主动关闭",
                CancellationToken.None);
        }
    }
}

客户端使用示例

// 使用示例
var client = new WebSocketClient("ws://localhost:5000/ws");

try
{
    await client.ConnectAsync();
    
    // 发送消息
    await client.SendAsync("Hello, WebSocket Server!");
    
    // 等待用户输入以保持连接
    Console.WriteLine("按任意键退出...");
    Console.ReadKey();
}
finally
{
    await client.CloseAsync();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值