探索WebSocket在ASP.NET Core中的实时通信应用与实现策略


前言

    在 ASP.NET Core 中集成 WebSocket 是一种实现实时通信的有效方式。WebSocket 提供了一个在单个长时间运行的连接上进行全双工通信的渠道。这意味着服务器和客户端都可以在任何时候开始发送数据。


一、创建 ASP.NET Core 项目

    首先,你需要有一个 ASP.NET Core 项目。你可以使用命令行工具(如 dotnet CLI)来创建一个新的项目:

dotnet new web -n WebSocketDemo  
cd WebSocketDemo

二、配置中间件以支持 WebSocket

1.启动类Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        builder.Services.AddControllers();
        ConfigureServices(builder.Services);
        // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();
        var app = builder.Build();var webSocketOptions = new WebSocketOptions
        {
            KeepAliveInterval = TimeSpan.FromSeconds(5)
        };
        //启动WebSockets
        app.UseWebSockets(webSocketOptions);
      
        app.UseAuthorization();
        app.MapControllers();
        app.Run();
    }public static void ConfigureServices(IServiceCollection services)
    {
        // 注册自定义服务  
        services.AddSingleton<WebSocketConnectionManager, WebSocketConnectionManager>();
        services.AddScoped<WebSocketHandler, WebSocketHandler>();
    }
}

    一定要添加app.UseWebSockets(webSocketOptions);,代表使用WebSocket协议。

2.WebSocket连接管理器

/// <summary>
/// WebSocket连接管理器
/// </summary>
public class WebSocketConnectionManager
{#region Constructorpublic WebSocketConnectionManager() 
    {
        _sockets = new ConcurrentDictionary<string, WebSocket>();
        _clientSendCommands = new ConcurrentDictionary<string, ConcurrentBag<string>>();
    }#endregion#region Property/// <summary>
    /// WebSocket连接池
    /// </summary>
    private readonly ConcurrentDictionary<string, WebSocket> _sockets;/// <summary>
    /// 客户端发送的命令池
    /// </summary>
    private readonly ConcurrentDictionary<string, ConcurrentBag<string>> _clientSendCommands;#endregion/// <summary>
    /// 添加WebSocket连接
    /// </summary>
    /// <param name="webSocket"></param>
    /// <returns></returns>
    public string AddSocket(string id,WebSocket webSocket) 
    {
        var socketId = id;
        if(string.IsNullOrWhiteSpace(id))
            socketId = Guid.NewGuid().ToString();
        if (_sockets.ContainsKey(id))
            _sockets.Remove(id,out _);
        _sockets.TryAdd(socketId, webSocket);
        return socketId;
    }/// <summary>
    /// 获取WebSocket
    /// </summary>
    /// <param name="socketId"></param>
    /// <returns></returns>
    public WebSocket? GetSocket(string socketId)
    {
        _sockets.TryGetValue(socketId, out var socket);
        return socket;
    }/// <summary>
    /// 根据Id 获取WebSocket
    /// </summary>
    /// <param name="socket"></param>
    /// <returns></returns>
    public string GetSocketId(WebSocket socket)
    {
        foreach (var (key, value) in _sockets)
        {
            if (value == socket)
            {
                return key;
            }
        }
        return string.Empty;
    }/// <summary>
    /// 根据Id移除WebSocket
    /// </summary>
    /// <param name="socketId"></param>
    public void RemoveSocket(string socketId)
    {
        _sockets.TryRemove(socketId, out _);
    }/// <summary>
    /// 移除WebSocket
    /// </summary>
    /// <param name="socket"></param>
    public void RemoveSocket(WebSocket socket)
    {
        var socketId = GetSocketId(socket);
        if(!string.IsNullOrWhiteSpace(socketId))
        {
            RemoveSocket(socketId);
        }
    }/// <summary>
    /// 获取所有的WebSocket
    /// </summary>
    /// <returns></returns>
    public List<WebSocket> GetAllSockets() 
    {
        var webSocketList = new List<WebSocket>();
        var keys = _sockets.Keys;
        foreach (var key in keys)
        {
            var socket = _sockets[key];
            webSocketList.Add(socket);
        }
        return webSocketList;
    }}

3.WebSocket事件管理器

public class WebSocketHandler
{#region Constructorpublic WebSocketHandler(
        WebSocketConnectionManager connectionManager,
        ILogger<WebSocketHandler> logger
) 
    {
        _connectionManager = connectionManager;
        _logger = logger;
    }#endregion#region Propertyprivate readonly WebSocketConnectionManager _connectionManager;
    private readonly ILogger<WebSocketHandler> _logger;#endregion/// <summary>
    /// 处理WebSocket
    /// </summary>
    /// <param name="context"></param>
    /// <param name="webSocket"></param>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task HandleWebSocket(HttpContext context, WebSocket webSocket,string id)
    {
        var socketId = _connectionManager.AddSocket(id,webSocket);
​
        _logger.LogInformation($"WebSocket connection established with ID {socketId}");
        try
        {
            while (webSocket.State == WebSocketState.Open)
            {
                var message = await ReceiveMessageAsync(webSocket);
                if (message != null)
                {
                    _logger.LogInformation($"Received message from ID {socketId}: {message}");
                    await BroadcastMessageAsync(socketId,message);
                }
            }
​
            _connectionManager.RemoveSocket(socketId);
            _logger.LogInformation($"WebSocket connection closed with ID {socketId}");
        }
        catch (WebSocketException ex)
        {
            _logger.LogError($"WebSocket error: {ex.Message}");
            _connectionManager.RemoveSocket(socketId);
        }
        catch (Exception ex)
        {
            // 处理其他可能的异常  
            _logger.LogError($"An error occurred: {ex.Message}");
            _connectionManager.RemoveSocket(socketId);
        }
    }private async Task<string?> ReceiveMessageAsync(WebSocket webSocket)
    {
        var buffer = new byte[1024];
        var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);if (result.CloseStatus.HasValue)
        {
            return null;
        }return Encoding.UTF8.GetString(buffer, 0, result.Count);
    }public async Task BroadcastMessageAsync(string socketId,string message)
    {
        var webSocket = _connectionManager.GetSocket(socketId);
        if (webSocket != null) 
        {
            if (webSocket.State == WebSocketState.Open)
            {
                await webSocket.SendAsync(Encoding.UTF8.GetBytes(message), WebSocketMessageType.Text, true, CancellationToken.None);
            }
            else if (webSocket.State == WebSocketState.Closed)
            {
                _connectionManager.RemoveSocket(socketId);
            }
        }
    }}

4.WebSocket连接入口

public class WebSocketController : ControllerBase
{#region Constructorpublic WebSocketController(
        ILogger<WebSocketController> logger,
        WebSocketConnectionManager webSocketConnectionManager,
        WebSocketHandler webSocketHandler)
    {
        _logger = logger;
        _webSocketConnectionManager = webSocketConnectionManager;
        _webSocketHandler = webSocketHandler;
    }#endregion#region Propertyprivate readonly WebSocketConnectionManager _webSocketConnectionManager;private readonly ILogger<WebSocketController> _logger;private readonly WebSocketHandler _webSocketHandler;#endregion[Route("/connect")]
    public async Task Get(string id)
    {
        if (HttpContext.WebSockets.IsWebSocketRequest)
        {
            var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
            await  _webSocketHandler.HandleWebSocket(HttpContext, webSocket, id);
        }
        else
        {
            HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }[HttpGet("/send")]
    public async Task SendMessage(string id,string message) 
    {
        await _webSocketHandler.BroadcastMessageAsync(id,message);
    }
}

     以上添加了一个WebSocketConnectionManager 连接管理器,是用于管理所有连接的WebSocket,另外添加了WebSocketHandler事件处理器,用于发送和接收消息。

三、客户端实现

     在客户端,你可以使用 JavaScript 的 WebSocket API 来建立连接并发送/接收数据。

<!DOCTYPE html>  
<html>  
<body>  
  
<script>  
    var ws = new WebSocket("ws://localhost:5000/connect?id=123");  
  
    ws.onopen = function(event) {  
        console.log("Connection open ...");  
        ws.send("Hello Server!");  
    };  
  
    ws.onmessage = function(event) {  
        console.log("Received from server: " + event.data);  
    };  
  
    ws.onclose = function(event) {  
        console.log("Connection closed.");  
    };  
</script>  
  
</body>  
</html>

总结

效果:
1.连接服务器,创建WebSocket连接
在这里插入图片描述
在这里插入图片描述
2.发送消息
在这里插入图片描述
3.连接服务器端接收到消息
在这里插入图片描述

“笑对人生,智慧同行!博客新文出炉,微信订阅号更新更实时,等你笑纳~”
在这里插入图片描述

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拥有必珍惜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值