asp.net core+websocket實現實時通信


1.創建簡易通訊協議

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Dw.RegApi.Models
{
    /// <summary>
    /// 通訊協議
    /// </summary>
    public class MsgTemplate
    {
        /// <summary>
        /// 接收人
        /// </summary>
        public string to_id { get; set; }
        /// <summary>
        /// 發送人
        /// </summary>
        public string from_id { get; set; }
        /// <summary>
        /// 發送人昵稱
        /// </summary>
        public string from_username { get; set; }
        /// <summary>
        /// 發送人頭像
        /// </summary>
        public string from_userpic { get; set; }
        /// <summary>
        /// 發送類型 text,voice等等
        /// </summary>
        public string type { get; set; }
        /// <summary>
        /// 發送內容 
        /// </summary>
        public string data { get; set; }
        /// <summary>
        /// 接收到的時間 
        /// </summary>
        public long time { get; set; }
    }
}

 

2.添加中間件ChatWebSocketMiddleware

using Dw.Util.Helper;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Dw.RegApi.Models
{
    /// <summary>
    /// WebSocket中間件ChatWebSocketMiddleware
    /// </summary>
    public class ChatWebSocketMiddleware
    {
        private static ConcurrentDictionary<string,WebSocket> _sockets = new ConcurrentDictionary<string,WebSocket>();

        private readonly RequestDelegate _next;

        /// <summary>
        /// WebSocket中間件
        /// </summary>
        /// <param name="next"></param>
        public ChatWebSocketMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        /// <summary>
        /// 執行
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task Invoke(HttpContext context)
        {
            if (!context.WebSockets.IsWebSocketRequest)
            {
                await _next.Invoke(context);
                return;
            }

            CancellationToken ct = context.RequestAborted;
            var currentSocket = await context.WebSockets.AcceptWebSocketAsync();

              string socketId_Expand = Guid.NewGuid().ToString();
              string socketId = context.Request.Query["sid"].ToString()+ socketId_Expand;

            if (!_sockets.ContainsKey(socketId))
            {
                _sockets.TryAdd(socketId, currentSocket);
            }
            //_sockets.TryRemove(socketId, out dummy);
            //_sockets.TryAdd(socketId, currentSocket);

            while (true)
            {
                if (ct.IsCancellationRequested)
                {
                    break;
                }

                string response = await ReceiveStringAsync(currentSocket, ct);
                NLogHelper.WriteInfo("WebSocket發送消息:" + response);
                MsgTemplate msg = JsonConvert.DeserializeObject<MsgTemplate>(response);

                if (string.IsNullOrEmpty(response))
                {
                    if (currentSocket.State != WebSocketState.Open)
                    {
                        break;
                    }

                    continue;
                }

                foreach (var socket in _sockets)
                {
                    if (socket.Value.State != WebSocketState.Open)
                    {
                        continue;
                    }
                    //控制只有接收者才能收到消息,並且用戶所有的客戶端都可以同步收到
                    if (socket.Key.Contains(msg.to_id))
                    {
                        await SendStringAsync(socket.Value, JsonConvert.SerializeObject(msg), ct);
                    }
                }
            }

            //_sockets.TryRemove(socketId, out dummy);

            await currentSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", ct);
            currentSocket.Dispose();
        }

        private static Task SendStringAsync(WebSocket socket, string data, CancellationToken ct = default(CancellationToken))
        {
            var buffer = Encoding.UTF8.GetBytes(data);
            var segment = new ArraySegment<byte>(buffer);
            return socket.SendAsync(segment, WebSocketMessageType.Text, true, ct);
        }

        private static async Task<string> ReceiveStringAsync(WebSocket socket, CancellationToken ct = default(CancellationToken))
        {
            var buffer = new ArraySegment<byte>(new byte[8192]);
            using (var ms = new MemoryStream())
            {
                WebSocketReceiveResult result;
                do
                {
                    ct.ThrowIfCancellationRequested();

                    result = await socket.ReceiveAsync(buffer, ct);
                    ms.Write(buffer.Array, buffer.Offset, result.Count);
                }
                while (!result.EndOfMessage);

                ms.Seek(0, SeekOrigin.Begin);
                if (result.MessageType != WebSocketMessageType.Text)
                {
                    return null;
                }

                using (var reader = new StreamReader(ms, Encoding.UTF8))
                {
                    return await reader.ReadToEndAsync();
                }
            }
        }
    }
}

 

3.在Startup.cs中使用中間件

            //WebSocket中間件
            var webSocketOptions = new WebSocketOptions()
            {
                //KeepAliveInterval - 向客戶端發送“ping”幀的頻率,以確保代理保持連接處於打開狀態。 默認值為 2 分鍾。
                KeepAliveInterval = TimeSpan.FromSeconds(120),
                //ReceiveBufferSize - 用於接收數據的緩沖區的大小。 高級用戶可能需要對其進行更改,以便根據數據大小調整性能。 默認值為 4 KB。
                ReceiveBufferSize = 4 * 1024
            };
            app.UseWebSockets(webSocketOptions);
            app.UseMiddleware<ChatWebSocketMiddleware>();

 

相關文檔:

https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/websockets?view=aspnetcore-3.1

https://www.cnblogs.com/besuccess/p/7043885.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM