NET7下用WebSocket做简易聊天室
步骤:
参考文章:.NET Core中WebSocket的使用详解_.net websocket-CSDN博客
GIT源码地址:公开仓库 (里面还有以前做的.NET FRAMEWORK的websocket示例代码)
namespace NetCore.WebSocketDemo.Models
{
///
/// websocket之间通信的JSON字符串转的实体类
///
public class Message
{
///
/// websocket对应的ID
///
public string SendClientId { set; get; }
///
/// 加入房间join 发送消息send_to_room 离开房间levea
///
public string action { set; get; }
///
/// 房间号
///
public string roomNo { set; get; }
///
/// 昵称
///
public string nick { set; get; }
///
/// 发送的消息内容
///
public string msg { set; get; }
}
}
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
namespace NetCore.WebSocketDemo.Models
{
///
/// 一个房间里的都用这个websocket
///
public class WebsocketClient
{
public string Id { set; get; }
public string RoomNo { set; get; }
public WebSocket WebSocket { set; get; }
public async Task SendMessageAsync(string text)
{
var recvBytes = Encoding.UTF8.GetBytes(text);
var sendBuffer = new ArraySegment(recvBytes);
try
{
await WebSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
catch (Exception ex)
{
throw ex;
}
}
}
}
namespace NetCore.WebSocketDemo.Models
{
///
/// websocket集合类,N个房间
///
public class WebsocketClientCollection
{
private static List _clients = new List();
public static void Add(WebsocketClient client)
{
_clients.Add(client);
}
public static void Remove(WebsocketClient client)
{
_clients.Remove(client);
}
public static WebsocketClient Get(string clientId)
{
var client = _clients.FirstOrDefault(c => c.Id == clientId);
return client;
}
public static List GetAll()
{
return _clients;
}
public static List GetClientsByRoomNo(string roomNo)
{
var client = _clients.Where(c => c.RoomNo == roomNo);
return client.ToList();
}
}
}
using Newtonsoft.Json;
using System.Net.WebSockets;
using System.Text;
namespace NetCore.WebSocketDemo.Models
{
///
/// programe里用 app.UseWebsocketHandlerMiddleware();
///
public static class WebsocketHandlerMiddlewareExtensions
{
public static IApplicationBuilder UseWebsocketHandlerMiddleware(
this IApplicationBuilder builder)
{
return builder.UseMiddleware();
}
}
///
/// websocket中间件
///
public class WebsocketHandlerMiddleware
{
private readonly RequestDelegate _next;
public WebsocketHandlerMiddleware( RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Path == "/ws")
{
//仅当网页执行new WebSocket("ws://localhost:5000/ws")时,后台会执行此逻辑
if (context.WebSockets.IsWebSocketRequest)
{
//后台成功接收到连接请求并建立连接后,前台的webSocket.onopen = function (event){}才执行
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
string clientId = Guid.NewGuid().ToString(); ;
var wsClient = new WebsocketClient
{
Id = clientId,
WebSocket = webSocket
};
try
{
await Handle(wsClient);
}
catch (Exception ex)
{
await context.Response.WriteAsync("closed");
}
}
else
{
context.Response.StatusCode = 404;
}
}
else
{
await _next(context);
}
}
private async Task Handle(WebsocketClient websocketClient)
{
WebsocketClientCollection.Add(websocketClient);
WebSocketReceiveResult clientData = null;
do
{
var buffer = new byte[1024 * 1];
//客户端与服务器成功建立连接后,服务器会循环异步接收客户端发送的消息,收到消息后就会执行Handle(WebsocketClient websocketClient)中的do{}while;直到客户端断开连接
//不同的客户端向服务器发送消息后台执行do{}while;时,websocketClient实参是不同的,它与客户端一一对应
//同一个客户端向服务器多次发送消息后台执行do{}while;时,websocketClient实参是相同的
clientData = await websocketClient.WebSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);
if (clientData.MessageType == WebSocketMessageType.Text && !clientData.CloseStatus.HasValue)
{
var msgString = Encoding.UTF8.GetString(buffer);
var message = JsonConvert.DeserializeObject(msgString);
message.SendClientId = websocketClient.Id;
HandleMessage(message);
}
} while (!clientData.CloseStatus.HasValue);
//关掉使用WebSocket连接的网页/调用webSocket.close()后,与之对应的后台会跳出循环
WebsocketClientCollection.Remove(websocketClient);
}
private void HandleMessage(Message message)
{
var client = WebsocketClientCollection.Get(message.SendClientId);
switch (message.action)
{
case "join":
client.RoomNo = message.roomNo;
client.SendMessageAsync($"{message.nick} join room {client.RoomNo} success .");
break;
case "send_to_room":
if (string.IsNullOrEmpty(client.RoomNo))
{
break;
}
var clients = WebsocketClientCollection.GetClientsByRoomNo(client.RoomNo);
clients.ForEach(c =>
{
c.SendMessageAsync(message.nick + " : " + message.msg);
});
break;
case "leave":
#region 通过把连接的RoomNo置空模拟关闭连接
var roomNo = client.RoomNo;
client.RoomNo = "";
#endregion
#region 后台关闭连接
//client.WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
//WebsocketClientCollection.Remove(client);
#endregion
client.SendMessageAsync($"{message.nick} leave room {roomNo} success .");
break;
default:
break;
}
}
}
}
var app = builder.Build();
#region 配置中间件,使用websocket
app.UseWebSockets(new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromSeconds(60),
ReceiveBufferSize = 1 * 1024
});
app.UseWebsocketHandlerMiddleware();
#endregion
简易websocket聊天室应用
房间号:
我的昵称: