首页 > 编程语言 >C# WebSocket Servers -- Fleck、SuperSocket、TouchSocke

C# WebSocket Servers -- Fleck、SuperSocket、TouchSocke

时间:2024-09-26 17:14:57浏览次数:9  
标签:ClinetList WebSocket SuperSocket C# await server client using public

最近在维护老项目,感觉内存一直都有问题,定位到问题是WebSocketServer的问题,了解了 Fleck、SuperSocket、TouchSocke 等开源项目 ,这里记录一下。

可能今后都不会用些轮子了,.net5、.net6、.net7、.net8 项目已经集成了WebSocket,只要  app.UseWebSockets() 代码就可以了,

详情见 WebSockets support in ASP.NET Core | Microsoft Learn

0. 控制台运行的代码

代码:https://gitee.com/Karl_Albright/csharp-web-socket-server

internal class Program
{
    static void Main(string[] args)
    {
        WebSockSvr server = new WebSockSvr();
        server.Start();
        server.SendDatas();
        Console.ReadLine();
    }
}

1. Fleck 

兼容 .NetFramework V4.0、.NetFramework V4.5、.NetCoreApp V2.0、.NetStandard V2.0

dotnet add package Fleck --version 1.2.0 
using Fleck;

namespace FleckDemo
{public class WebSockSvr
    {
        public List<IWebSocketConnection> ClinetList = new();
        private WebSocketServer service;
        public WebSockSvr() 
        {
            service = new WebSocketServer("ws://0.0.0.0:4040");
        }
        public void Start() 
        {
            service.Start(socket =>
            {
                socket.OnOpen = () =>
                {
                    Console.WriteLine("Open!");
                    ClinetList.Add(socket);
                };
                socket.OnClose = () =>
                {
                    Console.WriteLine("Close!");
                    ClinetList.Remove(socket);
                };
                socket.OnMessage = message =>
                {
                    Console.WriteLine(message);
                    ClinetList.ToList().ForEach(s => s.Send("Echo: " + message));
                };
            });
        }
        public void SendDatas()
        {
            for (int i = 0; i < 200; i++)
            {
                Task.Run(async () =>
                {
                    while (true)
                    {
                        try
                        {
                            for (int j = 0; j < ClinetList.Count; j++)
                            {
                                var sock = ClinetList[j];
                                if (sock.IsAvailable)
                                {
                                    await sock.Send($"Dev[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]");
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("出现异常:" + ex.Message + "\r\n" + ex.StackTrace);
                        }
                        finally
                        {
                            await Task.Delay(1000);
                        }
                    }
                });
            }
        }
    }
}

 

2. SuperSocket1.6 

截止到现在 superSocket 2.0版本还没正式发布,有beta.26版本,和1.6相比改动挺大的。

兼容 .NetFramework V4.6.1、.NetFramework V4.6.2、.NetFramework V4.7、.NetFramework V4.7.1、.NetFramework V4.7.2、.NetFramework V4.8、.NetFramework V4.8.1

dotnet add package SuperSocket --version 1.6.6.1
dotnet add package SuperSocket.Engine --version 1.6.6.1
dotnet add package SuperSocket.WebSocket --version 1.6.6.1
using SuperSocket.SocketBase;
using SuperSocket.WebSocket;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace SuperSocketDemo
{
    public class WebSockSvr
    {
        public List<WebSocketSession> ClinetList { get; set; } = new List<WebSocketSession>();
        private WebSocketServer server;
        public WebSockSvr()
        {
            server = new WebSocketServer();
            server.NewMessageReceived += Ws_NewMessageReceived;//当有信息传入时
            server.NewSessionConnected += Ws_NewSessionConnected;//当有用户连入时
            server.SessionClosed += Ws_SessionClosed;//当有用户退出时
            server.NewDataReceived += Ws_NewDataReceived;//当有数据传入时
        }

        public void Start()
        {
            if (server.Setup(4040))//绑定端口
                server.Start();//启动服务  
        }

        //public void SendDatas()
        //{
        //    //对当前已连接的所有会话进行广播
        //    foreach (var session in server.GetAllSessions())
        //    {
        //        session.Send($"Dev[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]");
        //        Thread.Sleep(1000);
        //    }
        //}
        public void SendDatas()
        {
            for (int i = 0; i < 200; i++)
            {
                Task.Run(async () =>
                {
                    while (true)
                    {
                        try
                        {
                            for (int j = 0; j < ClinetList.Count; j++)
                            {
                                var sock = ClinetList[j];
                                if (sock.Connected)
                                {
                                    sock.TrySend($"Dev[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]");
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("出现异常:" + ex.Message + "\r\n" + ex.StackTrace);
                        }
                        finally
                        {
                            await Task.Delay(10);
                        }
                    }
                });
            }

        }

        private void Ws_NewSessionConnected(WebSocketSession session)
        {
            ClinetList.Add(session);
        }

        private void Ws_NewMessageReceived(WebSocketSession session, string value)
        {

        }

        private void Ws_SessionClosed(WebSocketSession session, CloseReason value)
        {
            ClinetList.Remove(session);
        }

        private void Ws_NewDataReceived(WebSocketSession session, byte[] value)
        {

        }
    }
}

 

3. SuperSocket2.0.0-beta.26

兼容 .NetStandard V2.1、.Net5、.Net6、.Net7、.Net8

dotnet add package SuperSocket.WebSocket.Server --version 2.0.0-beta.26
using Microsoft.Extensions.Hosting;
using SuperSocket.Server;
using SuperSocket.Server.Abstractions;
using SuperSocket.Server.Host;
using SuperSocket.WebSocket.Server;

namespace SuperSocket2Demo
{
public class WebSockSvr { public List<WebSocketSession> ClinetList { get; set; } = new(); private IServer server; public WebSockSvr() { server = WebSocketHostBuilder.Create() .ConfigureSuperSocket(opts => { opts.AddListener(new ListenOptions { Ip = "127.0.0.1", Port = 4040 }); }) .UseSessionHandler((session) => { var sess = (WebSocketSession)session; ClinetList.Add(sess); return ValueTask.CompletedTask; }, (session, reason) => { var sess = (WebSocketSession)session; ClinetList.Remove(sess); return ValueTask.CompletedTask; }) .UseWebSocketMessageHandler(async (session, message) => { }) .BuildAsServer(); } public Task Start() { return server.StartAsync(); } public void SendDatas() { for (int i = 0; i < 200; i++) { Task.Run(async () => { while (true) { try { for (int j = 0; j < ClinetList.Count; j++) { var sock = ClinetList[j]; if (sock.State == SessionState.Connected) { await sock.SendAsync($"Dev[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]"); } } } catch (Exception ex) { Console.WriteLine("出现异常:" + ex.Message + "\r\n" + ex.StackTrace); } finally { await Task.Delay(10); } } }); } } } }

 

4. TouchSocket

目前兼容 .NetFramework V4.5、.NetFramework V4.6.2、.NetFramework V4.7.2、.NetFramework V4.8.1、.NetStandard V2.0、.NetStandard V2.1、.Net6、.Net7、.Net8

dotnet add package TouchSocket --version 2.1.5
dotnet add package TouchSocket.Http --version 2.1.5
dotnet add package TouchSocket.WebApi --version 2.1.5
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.Http;
using TouchSocket.Http.WebSockets;
using TouchSocket.Rpc;
using TouchSocket.Sockets;
using TouchSocket.WebApi;

namespace TouchSocketDemo.Core
{
    public class WebSockSvr
    {
        public List<IHttpSession> ClinetList { get; set; } = new List<IHttpSession>();
        private HttpService service;
        public WebSockSvr() 
        {
            service = new HttpService();
        }
        public async Task Start() 
        {
            await service.SetupAsync(new TouchSocketConfig()//加载配置
                 .SetListenIPHosts(4040)
                 .ConfigureContainer(a =>
                 {
                     a.AddConsoleLogger();
                 })
                 .ConfigurePlugins(a =>
                 {
                     a.UseWebSocket().SetWSUrl(null).UseAutoPong();
                     //a.Add<MyWebSocketPlugin>();
                     a.Add(typeof(IWebSocketHandshakedPlugin), async (IWebSocket client, HttpContextEventArgs e) =>
                     {
                         ClinetList.Add(client.Client);
                         await e.InvokeNext();
                     });
                     a.Add(typeof(IWebSocketClosingPlugin), async (IWebSocket client, ClosedEventArgs e) =>
                     {
                         ClinetList.Remove(client.Client);
                         await e.InvokeNext();
                     });

                     a.Add(typeof(IWebSocketReceivedPlugin), async (IWebSocket client, WSDataFrameEventArgs e) =>
                     {
                         switch (e.DataFrame.Opcode)
                         {
                             case WSDataType.Close:
                                 {
                                     await client.CloseAsync("断开");
                                 }
                                 return;
                             case WSDataType.Ping:
                                 await client.PongAsync();//收到ping时,一般需要响应pong
                                 break;
                             case WSDataType.Pong:
                                 break;
                             default:
                                 break;
                         }

                         await e.InvokeNext();
                     });

                     a.UseWebSocketReconnection();//a.Add<MyWebSocketPlugin>();
                 }));
            await service.StartAsync();
        }


        public void SendDatas()
        {
            for (int i = 0; i < 200; i++)
            {
                Task.Run(async () =>
                {
                    while (true)
                    {
                        try
                        {
                            var clientList = ClinetList.ToList();
                            for (int j = 0; j < clientList.Count; j++)
                            {
                                var sock = (HttpSessionClient)clientList[j];
                                if (sock.Online)
                                {
                                    await sock.WebSocket.SendAsync($"Dev[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]");
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("出现异常:" + ex.Message + "\r\n" + ex.StackTrace);
                        }
                        finally
                        {
                            await Task.Delay(10);
                        }
                    }
                });
            }
        }
public class MyWebSocketPlugin : PluginBase, IWebSocketHandshakingPlugin, IWebSocketHandshakedPlugin, IWebSocketReceivedPlugin { public MyWebSocketPlugin(ILog logger) { this.m_logger = logger; } public async Task OnWebSocketHandshaking(IWebSocket client, HttpContextEventArgs e) { if (client.Client is IHttpSessionClient socketClient) { //服务端 var id = socketClient.Id; } else if (client.Client is IHttpClient httpClient) { //客户端 } this.m_logger.Info("WebSocket正在连接"); await e.InvokeNext(); } public async Task OnWebSocketHandshaked(IWebSocket client, HttpContextEventArgs e) { this.m_logger.Info("WebSocket成功连接"); await e.InvokeNext(); } private readonly ILog m_logger; public async Task OnWebSocketReceived(IWebSocket client, WSDataFrameEventArgs e) { switch (e.DataFrame.Opcode) { case WSDataType.Close: {await client.CloseAsync("断开"); } return; case WSDataType.Ping:await client.PongAsync();//收到ping时,一般需要响应pong break; case WSDataType.Pong: this.m_logger.Info("Pong"); break; default: { //其他报文,需要考虑中继包的情况。所以需要手动合并 WSDataType.Cont类型的包。 //或者使用消息合并器 //获取消息组合器 var messageCombinator = client.GetMessageCombinator(); try { //尝试组合 if (messageCombinator.TryCombine(e.DataFrame, out var webSocketMessage)) { //组合成功,必须using释放模式 using (webSocketMessage) { //合并后的消息 var dataType = webSocketMessage.Opcode; //合并后的完整消息 var data = webSocketMessage.PayloadData; if (dataType == WSDataType.Text) { //按文本处理 } else if (dataType == WSDataType.Binary) { //按字节处理 } else { //可能是其他自定义协议 } } } } catch (Exception ex) { this.m_logger.Exception(ex); messageCombinator.Clear();//当组合发生异常时,应该清空组合器数据 } } break; } await e.InvokeNext(); } } } }

 

标签:ClinetList,WebSocket,SuperSocket,C#,await,server,client,using,public
From: https://www.cnblogs.com/KarlAlbright/p/18433768

相关文章

  • Capital许可证常见问题及解决方案
    在使用Capital软件时,许可证相关的问题是企业经常遇到的挑战。本文将列举Capital许可证的常见问题,并提供相应的解决方案,帮助企业轻松应对,确保软件的合规使用。一、许可证丢失或遗忘问题:企业可能由于各种原因遗失或忘记了Capital许可证的相关信息。解决方案:首先,企业应建立完善的......
  • C#实现的一个反向代理,实现了内网穿透,可以从公网服务器穿透到内网服务器
    ​ ​用C#实现的一个反向代理,可以从公网服务器穿透到内网服务器搭建的内网穿透长时间测试没有问题,效果比花生壳要好点。前提条件1.需要有自己的中转服务器好处1.流量没有限制2.速度比较快 测试脚本@echooffsetlocal set"URL=https://domain/interface2/......
  • Docker容器启动Redis设置密码并持久化
    启动命令dockerrun--namewh-redis-p6379:6379-v/root/RedisData:/data-d--restartunless-stoppedredis--appendonlyyes--requirepass'Your-password'dockerrun:启动一个新的Docker容器。--namewh-redis:给容器指定一个名称,容器名为wh-redis。指定名......
  • 冲刺CSP联训模拟1
    A.几何设\(f_{i,j,k}\)表示前\(i\)个字符,分为两部分,分别为\(x\)的几倍加\(x\)的前\(j\)位,\(y\)的几倍加\(y\)的前\(k\)位,是否合法分别判断下一位\(i+1\)能否与\(x\)的下一位\(j+1\)和\(y\)的下一位\(k+1\)匹配,匹配上了就转移.最终答案就是\(f_{|s|......
  • 探索EasyCVR视频融合平台:在视频编解码与转码领域的灵活性优势
    随着视频监控技术的飞速发展,各类应用场景对视频数据的处理需求日益复杂多样。从公共安全到智慧城市,再到工业监控,高效、灵活的视频处理能力成为衡量视频融合平台性能的重要标准。在众多解决方案中,EasyCVR视频融合平台凭借其在视频编解码、转码等能力上的强大灵活性,脱颖而出,成为行业......
  • SQL-数据库中ACID和事务性以及不同数据库的比较
    基本理念静态数据集是世界在某一特定瞬间的快照Staticdatasetsaresplit-secondsnapshotsofwhatevertheworldlookedlikeatonemoment世界就会继续前进,数据集需要跟上步伐以保持其有用性theworldmoveson,andthedatasetneedstocatchuptoremainusefu......
  • 【YashanDB知识库】YMP迁移oracle不兼容给用户授权高级包
    本文转自YashanDB官网,具体内容请见https://www.yashandb.com/newsinfo/7441382.html?templateId=1718516【标题】YMP迁移oracle不兼容给用户授权高级包【关键字】oracle迁移,高级包授权【问题描述】迁移评估任务中,oracle迁移YashanDB,YMP不兼容语句:grantexecuteonsys.dbms_sta......
  • EasyCVR智慧公园视频智能管理方案:赋能公园安全管理新高度
    随着城市化进程的加速,智慧城市建设已成为提升城市管理效率、增强居民生活质量的重要途径。智慧公园作为智慧城市的重要组成部分,其安全与管理水平直接影响着市民的休闲娱乐体验。EasyCVR智慧公园视频智能管理方案,正是基于这一背景应运而生,它集成了高清视频监控、智能分析、远程管理......
  • scss概念
    SCSS(SassyCSS)是CSS的一种预处理器语言,它在CSS的基础上提供了更多的功能和灵活性,使得样式表的编写和管理更加高效和便捷。以下是SCSS的一些优势:变量(Variables):SCSS允许使用变量来存储颜色、字体大小等数值,使得在整个样式表中统一调整这些值变得更加方便和可维护。嵌套(NestedRules):可......
  • DC-2通关详解
    DC-2与DC-1非常像,DC-2是另一个专门建立的易受攻击的实验室,目的是获得渗透测试领域的经验。与最初的DC-1一样,它是为初学者设计的。必须具备Linux技能并熟悉Linux命令行,还必须具有使用基本渗透测试工具的经验。DC-2一样有五个flag。渗透靶场目标是确定目标靶场使用ifconfig来......