51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

【CSharp】使用Fleck库实现WebSocket服务

前言 {#%E5%89%8D%E8%A8%80}

最近公司有个项目需要用C/S架构的桌面应用程序与B/S架构的网页程序进行通信做数据的交互功能。在网上查了一下资料,发现 Fleck 实现一个WebSocket服务竟然如此简单明了,于是在此记录和整理了一下 Fleck实现WebSocket服务的简单应用,希望对你有所帮助。

简介 {#%E7%AE%80%E4%BB%8B}

Fleck是一个用C#编写的轻量级WebSocket服务器库,它易于使用且高性能,同时保持代码的简洁性。

特点:

  • 无需继承:Fleck不需要你继承任何类,也不需要依赖于容器或额外的引用。

  • 无依赖 :Fleck不依赖于HttpListener​HTTP.sys​,这意味着它可以在Windows 7和Server 2008主机上工作。

  • 跨平台 :由于不依赖于HttpListener​,Fleck可以在非Windows平台上运行。

使用 {#%E4%BD%BF%E7%94%A8}

安装Fleck {#%E5%AE%89%E8%A3%85fleck}

通过NuGet包管理器安装Fleck库

Install-Package Fleck

创建WebSocket服务器 {#%E5%88%9B%E5%BB%BAwebsocket%E6%9C%8D%E5%8A%A1%E5%99%A8}

以下是一个简单的WebSocket服务器示例:

using Fleck;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

namespace WebSocketServiceDemo
{
public class WebSocketService
{
/// \<summary\> 客户端url以及其对应的Socket对象字典 \</summary\>
public IDictionary\<string, IWebSocketConnection\> dic_Sockets = new Dictionary\<string, IWebSocketConnection\>();


        private readonly object _lockObject = new object();

        private WebSocketServer _server;

        public WebSocketService()
        {
            //创建WebSocket服务端实例
            _server = new WebSocketServer("ws://0.0.0.0:9997");
            _server.RestartAfterListenError = true; //出错后进行重启
            _server.Start(ws=&gt;
            {
                ws.OnOpen = () =&gt;
                {   
                    WebSocket_OnOpen(ws);
                };
                ws.OnClose = () =&gt;
                {
                    WebSocket_OnClose(ws);
                };
                ws.OnMessage = message =&gt;
                {
                    Task.Run(() =&gt; { WebSocket_OnMessage(ws, message); });
                };
                ws.OnError = exp =&gt; 
                {
                    WebSocket_OnError(ws, exp);
                };
            });
        }

        private void WebSocket_OnOpen(IWebSocketConnection wsConnection)
        {
            string clientUrl = wsConnection.ConnectionInfo.ClientIpAddress + ":" + wsConnection.ConnectionInfo.ClientPort;
            AddSocket(clientUrl, wsConnection);
            Debug.WriteLine($"服务器和客户端网页:{clientUrl} 建立WebSock连接!当前连接数量:{dic_Sockets.Count}");
        }

        private void WebSocket_OnClose(IWebSocketConnection wsConnection)
        {
            string clientUrl = wsConnection.ConnectionInfo.ClientIpAddress + ":" + wsConnection.ConnectionInfo.ClientPort;
            if (dic_WSSockets.ContainsKey(clientUrl))
            RemoveSocket(clientUrl);
            Debug.WriteLine($"服务器和客户端网页:{clientUrl} 断开WebSock连接!当前连接数量:{dic_Sockets.Count}");
        }

        private void WebSocket_OnError(IWebSocketConnection wsConnection, Exception exception)
        {
            string clientUrl = wsConnection.ConnectionInfo.ClientIpAddress + ":" + wsConnection.ConnectionInfo.ClientPort;
            if (dic_WSSockets.ContainsKey(clientUrl))
            {
                RemoveSocket(clientUrl);
                Debug.WriteLine($"服务器和客户端网页:{clientUrl} 意外断开WebSock连接!当前连接数量:{dic_Sockets.Count}");
            }
        }

        private void WebSocket_OnMessage(IWebSocketConnection wsConnection, string msg)
        {
            string clientUrl = wsConnection.ConnectionInfo.ClientIpAddress + ":" + wsConnection.ConnectionInfo.ClientPort;
            Debug.WriteLine($"服务器:【收到】来客户端网页:{clientUrl}的信息:\n{msg}");
        }

        private bool RemoveSocket(string key)
        {
            lock (_lockObject)
            {
                return dic_WSSockets.Remove(key);
            }
        }

        private void AddSocket(string key, IWebSocketConnection socket)
        {
            lock (_lockObject)
            {
                dic_Sockets.Add(key, socket);
            }
        }
    }



`}
`

安全WebSockets (wss://) {#%E5%AE%89%E5%85%A8websockets-(wss%3A%2F%2F)}

要启用安全连接,需要使用wss​而不是ws​,并指向包含公钥和私钥的x509证书:

var server = new WebSocketServer("wss://0.0.0.0:9997");
server.Certificate = new X509Certificate2("MyCert.pfx");
server.Start(ws =>
{
    //...use as normal
});

子协议协商 {#%E5%AD%90%E5%8D%8F%E8%AE%AE%E5%8D%8F%E5%95%86}

Fleck允许你指定支持的子协议,并在WebSocketServer.SupportedSubProtocols​属性上进行协商。如果客户端请求中没有找到支持的子协议,连接将被关闭:

var server = new WebSocketServer("ws://0.0.0.0:9997");
server.SupportedSubProtocols = new []{ "superchat", "chat" };
server.Start(socket =>
{
    //socket.ConnectionInfo.NegotiatedSubProtocol 被填充
});

禁用Nagle算法 {#%E7%A6%81%E7%94%A8nagle%E7%AE%97%E6%B3%95}

你可以通过设置WebSocketConnection.ListenerSocket.NoDelay​true​来禁用Nagle算法:

var server = new WebSocketServer("ws://0.0.0.0:9997");
server.ListenerSocket.NoDelay = true;
server.Start(socket =>
{
    //子连接将不使用Nagle算法
});

监听错误后自动重启 {#%E7%9B%91%E5%90%AC%E9%94%99%E8%AF%AF%E5%90%8E%E8%87%AA%E5%8A%A8%E9%87%8D%E5%90%AF}

你可以通过设置WebSocketServer.RestartAfterListenError​true​来在监听错误后自动重启服务器:

var server = new WebSocketServer("ws://0.0.0.0:9997");
server.RestartAfterListenError = true;
server.Start(socket =>
{
    //...正常使用
});

自定义日志记录 {#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%97%A5%E5%BF%97%E8%AE%B0%E5%BD%95}

Fleck可以记录到Log4Net或任何其他第三方日志系统,只需覆盖FleckLog.LogAction​属性:

ILog logger = LogManager.GetLogger(typeof(FleckLog));
FleckLog.LogAction = (level, message, ex) =>
{
    switch (level)
    {
        case LogLevel.Debug:
            logger.Debug(message, ex);
            break;

        case LogLevel.Error:
            logger.Error(message, ex);
            break;

        case LogLevel.Warn:
            logger.Warn(message, ex);
            break;

        default:
            logger.Info(message, ex);
            break;
    }



`};
`


赞(0)
未经允许不得转载:工具盒子 » 【CSharp】使用Fleck库实现WebSocket服务