需求:模拟网页版微信进行通讯
直接上代码:
服务类:WebSocketMiddleware
public class WebSocketMiddleware
{
private readonly RequestDelegate _next;
public static Dictionary<string, WebSocket> _userConnections = new Dictionary<string, WebSocket>();
public WebSocketMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (!context.WebSockets.IsWebSocketRequest)
{
await _next(context);
return;
}
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
string UserId = context.Request.Query["UserId"].ToString();
// 将用户ID和WebSocket连接添加到映射中
_userConnections[UserId] = webSocket;
try
{
// 处理WebSocket消息
await HandleWebSocketMessages(UserId, webSocket);
}
catch (Exception e)
{
//写入日志
var bb = e.Message;
}
//移除WebSockets集合
if (_userConnections.ContainsKey(UserId))
{
_userConnections.Remove(UserId);
}
}
private async Task HandleWebSocketMessages(string SenderId, WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
WebSocketReceiveResult result;
while (webSocket.State == WebSocketState.Open)
{
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.CloseStatus.HasValue)
{
// 关闭WebSocket连接
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
return;
}
// 解析接收到的消息,获取发送者和接收者ID
// 假设消息格式是一个JSON对象,包含"from", "to", 和 "content"字段
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
var messageObj = JsonConvert.DeserializeObject<Message>(message);
if (messageObj == null) return;
//发送者标识,由后端这里进行补充或替换
messageObj.SenderId = SenderId;
// 如果是广播消息(to字段为空或特定值),则发送给所有用户
if (string.IsNullOrEmpty(messageObj.TargetId) || messageObj.TargetId == "0")
{
foreach (var connection in _userConnections.Values)
{
if (connection != webSocket) // 不要将消息发送回发送者
{
await connection.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
}
}
}
else
{
// 如果是点对点消息,则根据接收者ID路由到正确的连接
if (_userConnections.TryGetValue(messageObj.TargetId, out WebSocket targetWebSocket))
{
await targetWebSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
}
}
}
}
// 假设的Message类来表示WebSocket消息
private class Message
{
/// <summary>
/// 发送者标识
/// </summary>
public string SenderId { get; set; }
/// <summary>
/// 接受者标识
/// </summary>
public string TargetId { get; set; }
/// <summary>
/// 消息内容
/// </summary>
public string Content { get; set; }
/// <summary>
/// 表单内容
/// </summary>
public string From { get; set; }
}
}
中间件:Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseWebSockets();
app.Map("/OAWebSocket", (appWebSocket) =>
{
appWebSocket.UseMiddleware<WebSocketMiddleware>();
});
}
API:WebSocketController.cs
using Ht.Cloud.Common;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
namespace Ht.Cloud.Api.Controllers.Common
{
/// <summary>
/// websocket
/// </summary>
[Route("[controller]/[action]")]
[ApiController]
public class WebSocketController : ControllerBase
{
/// <summary>
///
/// </summary>
private Dictionary<string, WebSocket> _userConnections;
public WebSocketController()
{
_userConnections = new Dictionary<string, WebSocket>();
_userConnections = WebSocketMiddleware._userConnections;
// 假设你有代码来维护_userConnections字典
}
/// <summary>
/// 获取WebSocket的连接人数
/// </summary>
/// <returns></returns>
[HttpGet]
public int GetSumUser()
{
return _userConnections.Count;
}
}
}
HTML+JS:Model.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="../../js/jquery-3.3.1.js"></script>
<script>
var socket;
function star(index) {
//wws为https,如果是http改为ws,OAWebSocket为后端Startup中间件的配置(app.Map("/OAWebSocket",),UserId传输链接的用户标识
socket = new WebSocket('wss://localhost:44360/OAWebSocket?UserId=' + index + '');
textarea = document.getElementById('TextArea' + index + '')
socket.onopen = function (event) {
textarea.value += '用户标识' + index + ',已连接到WebSocket服务器:' + '\n';
//socket.send('你好,服务器!');
};
socket.onmessage = function (event) {
textarea.value += '接收消息:' + event.data + '\n';
};
socket.onclose = function (event) {
textarea.value += '用户标识' + index + ',已断开与WebSocket服务器的连接' + '\n';
};
socket.onerror = function (error) {
textarea.value += 'WebSocket Error:' + error + '\n';
};
}
function send() {
var Text1 = document.getElementById('Text1');
var Message = JSON.stringify({ "SenderId": "", "TargetId": "", "Content": Text1.value, "From": "" });
var textarea = document.getElementById('TextArea1');
textarea.value += "发送消息:" + Message + '\n';
socket.send(Message);
}
function send1() {
var Text2 = document.getElementById('Text2');
var Message = JSON.stringify({ "SenderId": "", "TargetId": "", "Content": Text2.value, "From": "" });
var textarea = document.getElementById('TextArea2');
textarea.value += "发送消息:" + Message + '\n';
socket.send(Message);
}
// 当需要关闭WebSocket连接时
function end() {
if (socket.readyState === WebSocket.OPEN) {
socket.close(); // 发送关闭帧给服务器
}
}
</script>
<script>
setInterval(updateUserCount, 5000); // 每5秒更新一次
function updateUserCount() {
fetch('https://localhost:44360/WebSocket/GetSumUser') // 调用后端API
.then(response => response.json()) // 解析返回的JSON
.then(data => {
// 假设你有一个元素用于显示用户数,例如<span id="userCount"></span>
document.getElementById('userCount').textContent = data; // 更新页面上的用户数
})
.catch(error => {
console.error('Error:', error);
});
}
</script>
</head>
<body>
当前连接人数<span id="userCount">0</span>
<br />
<input id="btn-kslj" type="button" onclick="star(1)" value="客户端标识1,开始连接" /><input id="btn-gb" type="button" onclick="end()" value="关闭链接" /><br />
接收内容:<textarea id="TextArea1" rows="2" style="width:600px; height:300px;" cols="20"></textarea>
发送内容:<input id="Text1" type="text" />
<input id="fasong" type="button" onclick="send()" value="发送" />
<br />
<input id="btn-kslj2" type="button" onclick="star(2)" value="客户端标识2,开始连接" /><br />
接收内容:<textarea id="TextArea2" rows="2" style="width:600px; height:300px;" cols="20"></textarea>
发送内容:<input id="Text2" type="text" />
<input id="fasong" type="button" onclick="send1()" value="发送" />
</body>
</html>