【CSharp】使用Fleck库实现WebSocket服务
前言
最近公司有个项目需要用C/S架构的桌面应用程序与B/S架构的网页程序进行通信做数据的交互功能。在网上查了一下资料,发现 Fleck 实现一个WebSocket服务竟然如此简单明了,于是在此记录和整理了一下 Fleck 实现WebSocket服务的简单应用,希望对你有所帮助。
简介
Fleck 是一个用C#编写的轻量级WebSocket服务器库,它易于使用且高性能,同时保持代码的简洁性。
特点:
无需继承:Fleck不需要你继承任何类,也不需要依赖于容器或额外的引用。
无依赖:Fleck不依赖于
HttpListener
或HTTP.sys
,这意味着它可以在Windows 7和Server 2008主机上工作。跨平台:由于不依赖于
HttpListener
,Fleck可以在非Windows平台上运行。
使用
安装Fleck
通过NuGet包管理器安装Fleck库
Install-Package Fleck
创建WebSocket服务器
以下是一个简单的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=>
{
ws.OnOpen = () =>
{
WebSocket_OnOpen(ws);
};
ws.OnClose = () =>
{
WebSocket_OnClose(ws);
};
ws.OnMessage = message =>
{
Task.Run(() => { WebSocket_OnMessage(ws, message); });
};
ws.OnError = exp =>
{
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://)
要启用安全连接,需要使用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
});
子协议协商
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算法
你可以通过设置WebSocketConnection.ListenerSocket.NoDelay
为true
来禁用Nagle算法:
var server = new WebSocketServer("ws://0.0.0.0:9997");
server.ListenerSocket.NoDelay = true;
server.Start(socket =>
{
//子连接将不使用Nagle算法
});
监听错误后自动重启
你可以通过设置WebSocketServer.RestartAfterListenError
为true
来在监听错误后自动重启服务器:
var server = new WebSocketServer("ws://0.0.0.0:9997");
server.RestartAfterListenError = true;
server.Start(socket =>
{
//...正常使用
});
自定义日志记录
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;
}
};
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果