文章目录
前言
在 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 Constructor
public 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 Constructor
public WebSocketHandler(
WebSocketConnectionManager connectionManager,
ILogger<WebSocketHandler> logger
)
{
_connectionManager = connectionManager;
_logger = logger;
}
#endregion
#region Property
private 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 Constructor
public WebSocketController(
ILogger<WebSocketController> logger,
WebSocketConnectionManager webSocketConnectionManager,
WebSocketHandler webSocketHandler)
{
_logger = logger;
_webSocketConnectionManager = webSocketConnectionManager;
_webSocketHandler = webSocketHandler;
}
#endregion
#region Property
private 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.连接服务器端接收到消息
“笑对人生,智慧同行!博客新文出炉,微信订阅号更新更实时,等你笑纳~”