C# WebSocket Fleck 源码解读

最近在维护公司旧项目,偶然发现使用Fleck实现的WebSocket主动推送功能,(由于前端页面关闭时WebSocket Server中执行了多次OnClose事件回调并且打印了大量的关闭日志,),后来我特地看了源码,这里做一些分享

github: https://github.com/statianzo/Fleck

 在源码中,作者在 Samples 项目中贴心的准备了Server端和 前端Html文件供调试

 打开后,我们稍微改动一下Server.cs类,模拟实际场景向客户端主动推送消息。

运行ConsoleApp项目,随后在浏览器中打开client.html,我们就可以看到客户端接收到很多主动推送的消息

关闭客户端后,此时我们会发现控制台上打印了好多“Close!”,并且抛出了异常,异常是从System.Net.Sockets.NetworkStream 抛出,说我们访问了已释放的对象。

 大概猜测的是程序并发太高了,Socket已经关闭释放的同时,我们任然在向流写入byte字节发送消息。

 

接下来我们读一下源码

首先是 WebSocketServer.cs,构造方法中创建了 System.Net.Sockets.Socket类,并传递给 Fleck.SocketWrapper,后续和Socket相关的操作都是由SocketWrapper实例进行执行。SupportDualStack为True时表示启用IPV6

 随后我们看一下 WebSocketServer.Start() 方法,方法的入参是一个Action,IWebSocketConnection 中我们定义了OnOpen、OnClose、OnMessage等方法。

Start()方法中给SocketWrapper(或System.Net.Sockets.Socket类)类绑定了侦听地址和端口。

ListenForClients() 方法为开始接收连接(Accept),如果有连接,则调用OnClientConnect()方法,OnClientConnect()方法调用中如果出现异常,则执行重启Socket工作。

 

 我们再来看看OnClientConnect()方法做了什么,ListenForClients() 方法是继续侦听客户端连接,随后创建了WebSocketConnection类对象,然后开始connection.StartReceiving() 也就是读取消息内容。

我们可以简单的看一下Fleck.SocketWrapper类的实现,特别是Accept()方法和Receive()方法,其实就是Task执行BeginAccept()、EndAccept()、BeginRead() 和 EndRead() 方法,如果调用时出现异常,则执行Action<Exception>()方法。

接下来我们看一下WebSocketConnection类,首先是构造方法,

  •   socket:连接Socket实例。
  •   initialize:是我们在WebSocketServer 中配置的OnOpen、OnClose、OnMessage等方法。
  •   handlerFactory:是通过工厂模式创建出对应的Handle对象,其中实现了 Draft76Handler、Hybi13Handler、FlashSocketPolicyRequestHandler 等几种类,将收到的byte[]序列化成对应的消息。
  •   parseRequest:是RequestParser.Parse方法的委托,将byte[]通过UTF8序列化成中文,再通过正则表达式提取关键信息生成WebSocketHttpRequest对象。

其次是Read(List<byte>, byte[]) 方法。就是调用SocketWrapper(或System.Net.Sockets.Socket类)的 Receive()方法读取byte[]并交给Handle对象进行处理,如果byte[]长度为0,则表示关闭断开

最后是SendBytes(byte[], Action)方法,就是调用SocketWrapper(或System.Net.Sockets.Socket类)的 Send()方法,如果发送不成功,则会调用CloseSocket()方法关闭Socket(这就是为什么连接只有一个但多次触发OnClose事件原因)

 

Fleck 的核心功能已经讲解完了,其他类还有 WebSocketConnectionInfo、QueuedStream、SubProtocolNegotiator等类基本也是比较简单,这里就不展开讲解了。

Fleck 源码 用了装饰者模式、工厂模式等设计模式,还很优雅的处理方法执行失败的异常方式,对委托的使用也是值得我们学习的。

 

posted @ 2024-08-22 23:24  Karl_Albright  阅读(400)  评论(1编辑  收藏  举报