Cowboy 开源 WebSocket 网络库

简介:

Cowboy.WebSockets 是一个托管在 GitHub 上的基于 .NET/C# 实现的开源 WebSocket 网络库,其完整的实现了 RFC 6455 (The WebSocket Protocol) 协议标准,并部分实现了 RFC 7692 (Compression Extensions for WebSocket) 协议标准。

WebSocket 可理解为建立在 TCP 连接通道上的更进一步的握手,并确定了消息封装格式。

通过定义控制帧 (Control Frame) 和数据帧 (Data Frame) 来控制通道内的通信和数据传输,下图用使用 ABNF 格式描述了帧头部的格式。

Cowboy.WebSockets 中对于 WebSocket 的 Client/Server 分别做了实现,分别对应代码中的:

Cowboy.WebSockets 的内部实现是基于 Cowboy.Sockets 中的 TAP 模式的 AsyncTcpSocketServer 和 AsyncTcpSocketClient 。关于 Cowboy.Sockets 可以参考文章《C#高性能TCP服务的多种实现方式》。

可通过 NuGet 查找 Cowboy 来获取 nuget 包。

WebSocket 服务端应用

实现 AsyncWebSocketServerModule 抽象类,其中 ModulePath 对应着 "ws://host:port/path" 中的 path 部分。可以实现多个 Module,将多个 Module 注入到 AsyncWebSocketServerModuleCatalog 中,或者采用反射机制等自动发现 Module。

复制代码
  public class TestWebSocketModule : AsyncWebSocketServerModule
  {
      public TestWebSocketModule()
          : base(@"/test")
      {
      }
  
      public override async Task OnSessionStarted(AsyncWebSocketSession session)
      {
          Console.WriteLine(string.Format("WebSocket session [{0}] has connected.", session.RemoteEndPoint));
          await Task.CompletedTask;
      }
  
      public override async Task OnSessionTextReceived(AsyncWebSocketSession session, string text)
      {
          Console.Write(string.Format("WebSocket session [{0}] received Text --> ", session.RemoteEndPoint));
          Console.WriteLine(string.Format("{0}", text));
  
          await session.SendTextAsync(text);
      }
  
      public override async Task OnSessionBinaryReceived(AsyncWebSocketSession session, byte[] data, int offset, int count)
      {
          var text = Encoding.UTF8.GetString(data, offset, count);
          Console.Write(string.Format("WebSocket session [{0}] received Binary --> ", session.RemoteEndPoint));
          Console.WriteLine(string.Format("{0}", text));
  
          await session.SendBinaryAsync(Encoding.UTF8.GetBytes(text));
      }
  
      public override async Task OnSessionClosed(AsyncWebSocketSession session)
      {
          Console.WriteLine(string.Format("WebSocket session [{0}] has disconnected.", session.RemoteEndPoint));
          await Task.CompletedTask;
      }
  }
复制代码

实例化 AsyncWebSocketServer,并将 AsyncWebSocketServerModuleCatalog 实例注入,即可启动 WebSocket 的服务端监听。

复制代码
  class Program
  {
      static AsyncWebSocketServer _server;
  
      static void Main(string[] args)
      {
          NLogLogger.Use();
  
          try
          {
              var catalog = new AsyncWebSocketServerModuleCatalog();
              catalog.RegisterModule(new TestWebSocketModule());
  
              var config = new AsyncWebSocketServerConfiguration();
              //config.SslEnabled = true;
              //config.SslServerCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(@"D:\\Cowboy.pfx", "Cowboy");
              //config.SslPolicyErrorsBypassed = true;
  
              _server = new AsyncWebSocketServer(22222, catalog, config);
              _server.Listen();
  
              Console.WriteLine("WebSocket server has been started on [{0}].", _server.ListenedEndPoint);
              Console.WriteLine("Type something to send to clients...");
              while (true)
              {
                  try
                  {
                      string text = Console.ReadLine();
                      if (text == "quit")
                          break;
                      Task.Run(async () =>
                      {
                          //await _server.BroadcastText(text);
                          //Console.WriteLine("WebSocket server [{0}] broadcasts text -> [{1}].", _server.ListenedEndPoint, text);
                          await _server.BroadcastBinaryAsync(Encoding.UTF8.GetBytes(text));
                          Console.WriteLine("WebSocket server [{0}] broadcasts binary -> [{1}].", _server.ListenedEndPoint, text);
                      });
                  }
                  catch (Exception ex)
                  {
                      Console.WriteLine(ex.Message);
                  }
              }
  
              _server.Shutdown();
              Console.WriteLine("WebSocket server has been stopped on [{0}].", _server.ListenedEndPoint);
          }
          catch (Exception ex)
          {
              Logger.Get<Program>().Error(ex.Message, ex);
          }
  
          Console.ReadKey();
      }
  }
复制代码

WebSocket 客户端应用

客户端侧在实例化 AsyncWebSocketClient 时有两种方式:

  1. 实现 IAsyncWebSocketClientMessageDispatcher 接口;
  2. 直接构造函数注入接受各种事件的 Func<> 实现;
复制代码
  public interface IAsyncWebSocketClientMessageDispatcher
  {
      Task OnServerConnected(AsyncWebSocketClient client);
      Task OnServerTextReceived(AsyncWebSocketClient client, string text);
      Task OnServerBinaryReceived(AsyncWebSocketClient client, byte[] data, int offset, int count);
      Task OnServerDisconnected(AsyncWebSocketClient client);
  
      Task OnServerFragmentationStreamOpened(AsyncWebSocketClient client, byte[] data, int offset, int count);
      Task OnServerFragmentationStreamContinued(AsyncWebSocketClient client, byte[] data, int offset, int count);
      Task OnServerFragmentationStreamClosed(AsyncWebSocketClient client, byte[] data, int offset, int count);
  }
复制代码

下面的 DEMO 采用了方式二。

复制代码
  class Program
  {
      static AsyncWebSocketClient _client;
  
      static void Main(string[] args)
      {
          NLogLogger.Use();
  
          Task.Run(async () =>
          {
              try
              {
                  var config = new AsyncWebSocketClientConfiguration();
                  //config.SslTargetHost = "Cowboy";
                  //config.SslClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate2(@"D:\\Cowboy.cer"));
                  //config.SslPolicyErrorsBypassed = true;
  
                  //var uri = new Uri("ws://echo.websocket.org/");
                  //var uri = new Uri("wss://127.0.0.1:22222/test");
                  var uri = new Uri("ws://127.0.0.1:22222/test");
                  _client = new AsyncWebSocketClient(uri,
                      OnServerTextReceived,
                      OnServerBinaryReceived,
                      OnServerConnected,
                      OnServerDisconnected,
                      config);
                  await _client.Connect();
  
                  Console.WriteLine("WebSocket client has connected to server [{0}].", uri);
                  Console.WriteLine("Type something to send to server...");
                  while (_client.State == WebSocketState.Open)
                  {
                      try
                      {
                          string text = Console.ReadLine();
                          if (text == "quit")
                              break;
                          Task.Run(async () =>
                          {
                              //await _client.SendText(text);
                              //Console.WriteLine("Client [{0}] send text -> [{1}].", _client.LocalEndPoint, text);
                              await _client.SendBinaryAsync(Encoding.UTF8.GetBytes(text));
                              Console.WriteLine("Client [{0}] send binary -> [{1}].", _client.LocalEndPoint, text);
                          }).Forget();
                      }
                      catch (Exception ex)
                      {
                          Console.WriteLine(ex.Message);
                      }
                  }
  
                  await _client.Close(WebSocketCloseCode.NormalClosure);
                  Console.WriteLine("WebSocket client has disconnected from server [{0}].", uri);
              }
              catch (Exception ex)
              {
                  Logger.Get<Program>().Error(ex.Message, ex);
              }
          }).Wait();
  
          Console.ReadKey();
      }
  
      private static async Task OnServerConnected(AsyncWebSocketClient client)
      {
          Console.WriteLine(string.Format("WebSocket server [{0}] has connected.", client.RemoteEndPoint));
          await Task.CompletedTask;
      }
  
      private static async Task OnServerTextReceived(AsyncWebSocketClient client, string text)
      {
          Console.Write(string.Format("WebSocket server [{0}] received Text --> ", client.RemoteEndPoint));
          Console.WriteLine(string.Format("{0}", text));
  
          await Task.CompletedTask;
      }
  
      private static async Task OnServerBinaryReceived(AsyncWebSocketClient client, byte[] data, int offset, int count)
      {
          var text = Encoding.UTF8.GetString(data, offset, count);
          Console.Write(string.Format("WebSocket server [{0}] received Binary --> ", client.RemoteEndPoint));
          Console.WriteLine(string.Format("{0}", text));
  
          await Task.CompletedTask;
      }
  
      private static async Task OnServerDisconnected(AsyncWebSocketClient client)
      {
          Console.WriteLine(string.Format("WebSocket server [{0}] has disconnected.", client.RemoteEndPoint));
          await Task.CompletedTask;
      }
  }
复制代码

相关资料





本文转自匠心十年博客园博客,原文链接:http://www.cnblogs.com/gaochundong/p/cowboy_websockets.html,如需转载请自行联系原作者

目录
相关文章
|
24天前
|
安全 Linux 网络安全
nmap 是一款强大的开源网络扫描工具,能检测目标的开放端口、服务类型和操作系统等信息
nmap 是一款强大的开源网络扫描工具,能检测目标的开放端口、服务类型和操作系统等信息。本文分三部分介绍 nmap:基本原理、使用方法及技巧、实际应用及案例分析。通过学习 nmap,您可以更好地了解网络拓扑和安全状况,提升网络安全管理和渗透测试能力。
94 5
|
3月前
|
JavaScript 前端开发 API
网络请求库 – axios库
网络请求库 – axios库
205 60
|
2月前
|
网络协议 物联网 虚拟化
|
24天前
|
网络协议 Unix Linux
精选2款C#/.NET开源且功能强大的网络通信框架
精选2款C#/.NET开源且功能强大的网络通信框架
|
3月前
|
数据采集 JSON API
🎓Python网络请求新手指南:requests库带你轻松玩转HTTP协议
本文介绍Python网络编程中不可或缺的HTTP协议基础,并以requests库为例,详细讲解如何执行GET与POST请求、处理响应及自定义请求头等操作。通过简洁易懂的代码示例,帮助初学者快速掌握网络爬虫与API开发所需的关键技能。无论是安装配置还是会话管理,requests库均提供了强大而直观的接口,助力读者轻松应对各类网络编程任务。
122 3
|
3月前
|
机器学习/深度学习 JSON API
HTTP协议实战演练场:Python requests库助你成为网络数据抓取大师
在数据驱动的时代,网络数据抓取对于数据分析、机器学习等至关重要。HTTP协议作为互联网通信的基石,其重要性不言而喻。Python的`requests`库凭借简洁的API和强大的功能,成为网络数据抓取的利器。本文将通过实战演练展示如何使用`requests`库进行数据抓取,包括发送GET/POST请求、处理JSON响应及添加自定义请求头等。首先,请确保已安装`requests`库,可通过`pip install requests`进行安装。接下来,我们将逐一介绍如何利用`requests`库探索网络世界,助你成为数据抓取大师。在实践过程中,务必遵守相关法律法规和网站使用条款,做到技术与道德并重。
55 2
|
3月前
|
数据采集 存储 JSON
从零到一构建网络爬虫帝国:HTTP协议+Python requests库深度解析
在网络数据的海洋中,网络爬虫遵循HTTP协议,穿梭于互联网各处,收集宝贵信息。本文将从零开始,使用Python的requests库,深入解析HTTP协议,助你构建自己的网络爬虫帝国。首先介绍HTTP协议基础,包括请求与响应结构;然后详细介绍requests库的安装与使用,演示如何发送GET和POST请求并处理响应;最后概述爬虫构建流程及挑战,帮助你逐步掌握核心技术,畅游数据海洋。
73 3
|
3月前
|
数据采集 网络协议 API
HTTP协议大揭秘!Python requests库实战,让网络请求变得简单高效
【9月更文挑战第13天】在数字化时代,互联网成为信息传输的核心平台,HTTP协议作为基石,定义了客户端与服务器间的数据传输规则。直接处理HTTP请求复杂繁琐,但Python的`requests`库提供了一个简洁强大的接口,简化了这一过程。HTTP协议采用请求与响应模式,无状态且结构化设计,使其能灵活处理各种数据交换。
86 8
|
3月前
|
JSON API 开发者
Python网络编程新纪元:urllib与requests库,让你的HTTP请求无所不能
【9月更文挑战第9天】随着互联网的发展,网络编程成为现代软件开发的关键部分。Python凭借简洁、易读及强大的特性,在该领域展现出独特魅力。本文介绍了Python标准库中的`urllib`和第三方库`requests`在处理HTTP请求方面的优势。`urllib`虽API底层但功能全面,适用于深入控制HTTP请求;而`requests`则以简洁的API和人性化设计著称,使HTTP请求变得简单高效。两者互补共存,共同推动Python网络编程进入全新纪元,无论初学者还是资深开发者都能从中受益。
52 7
|
3月前
|
网络协议 Linux C++
超级好用的C++实用库之网络
超级好用的C++实用库之网络
52 0