Recently in the maintenance of the old project, the feeling that the memory has been a problem , to locate the problem is a WebSocketServer problem , to understand the Fleck, SuperSocket, TouchSocke and other open-source projects , here to record .
The .net5, .net6, .net7, and .net8 projects have integrated WebSocket with just the () code, for more information seeWebSockets support in Core | Microsoft Learn。
0. Console-run code
Code:/Karl_Albright/csharp-web-socket-server
internal class Program { static void Main(string[] args) { WebSockSvr server = new WebSockSvr(); (); (); (); } }
1. Fleck
Compatible with .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 FleckWebSockSvr { public List<IWebSocketConnection> ClinetList = new(); private WebSocketServer service; public FleckWebSockSvr() { service = new WebSocketServer("ws://0.0.0.0:4040"); } public void Start() { (socket => { = () => { ("Open!"); (socket); }; = () => { ("Close!"); (socket); }; = message => { (message); ().ForEach(s => ("Echo: " + message)); }; }); } public void SendDatas() { for (int i = 0; i < 200; i++) { (async () => { while (true) { try { for (int j = 0; j < ; j++) { var sock = ClinetList[j]; if () { await ($"Dev[{("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]"); } } } catch (Exception ex) { ("Anomalies occur:" + + "\r\n" + ); } finally { await (1000); } } }); } } } }
2. SuperSocket1.6
As of now superSocket version 2.0 has not been officially released, there is beta.26 version, compared with 1.6 the changes are quite big.
compatibility .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 --version 1.6.6.1 dotnet add package --version 1.6.6.1
using ; using ; using System; using ; using ; namespace SuperSocketDemo { public class WebSockSvr { public List<WebSocketSession> ClinetList { get; set; } = new List<WebSocketSession>(); private WebSocketServer server; public WebSockSvr() { server = new WebSocketServer(); += Ws_NewMessageReceived;//When a message comes in += Ws_NewSessionConnected;//When a user connects += Ws_SessionClosed;//When a user logs out += Ws_NewDataReceived;//When there is incoming data } public void Start() { if ((4040))//Bind Ports ();//Starting services } //public void SendDatas() //{ // //Broadcast to all currently connected sessions // foreach (var session in ()) // { // ($"Dev[{("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]"); // (1000); // } //} public void SendDatas() { for (int i = 0; i < 200; i++) { (async () => { while (true) { try { for (int j = 0; j < ; j++) { var sock = ClinetList[j]; if () { ($"Dev[{("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]"); } } } catch (Exception ex) { ("Anomalies occur:" + + "\r\n" + ); } finally { await (10); } } }); } } private void Ws_NewSessionConnected(WebSocketSession session) { (session); } private void Ws_NewMessageReceived(WebSocketSession session, string value) { } private void Ws_SessionClosed(WebSocketSession session, CloseReason value) { (session); } private void Ws_NewDataReceived(WebSocketSession session, byte[] value) { } } }
3. SuperSocket2.0.0-beta.26
Compatible with .NetStandard V2.1, .Net5, .Net6, .Net7, .Net8
dotnet add package --version 2.0.0-beta.26
using ; using ; using ; using ; using ; namespace SuperSocket2Demo {public class WebSockSvr { public List<WebSocketSession> ClinetList { get; set; } = new(); private IServer server; public WebSockSvr() { server = () .ConfigureSuperSocket(opts => { (new ListenOptions { Ip = "127.0.0.1", Port = 4040 }); }) .UseSessionHandler((session) => { var sess = (WebSocketSession)session; (sess); return ; }, (session, reason) => { var sess = (WebSocketSession)session; (sess); return ; }) .UseWebSocketMessageHandler(async (session, message) => { }) .BuildAsServer(); } public Task Start() { return (); } public void SendDatas() { for (int i = 0; i < 200; i++) { (async () => { while (true) { try { for (int j = 0; j < ; j++) { var sock = ClinetList[j]; if ( == ) { await ($"Dev[{("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]"); } } } catch (Exception ex) { ("Anomalies occur:" + + "\r\n" + ); } finally { await (10); } } }); } } } }
4. TouchSocket
Currently compatible with .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 --version 2.1.5 dotnet add package --version 2.1.5
using System; using ; using ; using ; using ; using ; using ; using ; using ; using ; namespace { 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 (new TouchSocketConfig()//Load Configuration .SetListenIPHosts(4040) .ConfigureContainer(a => { (); }) .ConfigurePlugins(a => { ().SetWSUrl(null).UseAutoPong(); //<MyWebSocketPlugin>(); (typeof(IWebSocketHandshakedPlugin), async (IWebSocket client, HttpContextEventArgs e) => { (); await (); }); (typeof(IWebSocketClosingPlugin), async (IWebSocket client, ClosedEventArgs e) => { (); await (); }); (typeof(IWebSocketReceivedPlugin), async (IWebSocket client, WSDataFrameEventArgs e) => { switch () { case : { await ("turn off (electric switch)"); } return; case : await ();//When you receive a ping, you generally need to respond with a pong break; case : break; default: break; } await (); }); ();//<MyWebSocketPlugin>(); })); await (); } public void SendDatas() { for (int i = 0; i < 200; i++) { (async () => { while (true) { try { var clientList = (); for (int j = 0; j < ; j++) { var sock = (HttpSessionClient)clientList[j]; if () { await ($"Dev[{("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]"); } } } catch (Exception ex) { ("Anomalies occur:" + + "\r\n" + ); } finally { await (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 ( is IHttpSessionClient socketClient) { //server-side var id = ; } else if ( is IHttpClient httpClient) { //client (computing) } this.m_logger.Info("WebSocket is connecting"); await (); } public async Task OnWebSocketHandshaked(IWebSocket client, HttpContextEventArgs e) { this.m_logger.Info("WebSocket successfully connected"); await (); } private readonly ILog m_logger; public async Task OnWebSocketReceived(IWebSocket client, WSDataFrameEventArgs e) { switch () { case : {await ("turn off (electric switch)"); } return; case :await ();//When you receive a ping, you generally need to respond with a pong break; case : this.m_logger.Info("Pong"); break; default: { //For other messages, you need to consider the case of relay packets. So you need to manually merge the packet types. //Or use a message merger //Get Message Composer var messageCombinator = (); try { //Try combinations if ((, out var webSocketMessage)) { //Successful combination, must be USING release mode using (webSocketMessage) { //Merged messages var dataType = ; //The full message after the merger var data = ; if (dataType == ) { //text-based processing } else if (dataType == ) { //byte-by-byte processing } else { //Possibly other custom protocols } } } } catch (Exception ex) { this.m_logger.Exception(ex); ();//When an exception occurs in the combination, the combiner data should be cleared } } break; } await (); } } } }