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(, 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;
}
}

相关资料

本篇文章《Cowboy 开源 WebSocket 网络库》由 Dennis Gao 发表自博客园个人博客,未经作者本人同意禁止以任何的形式转载,任何自动的或人为的爬虫转载行为均为耍流氓。

Cowboy 开源 WebSocket 网络库的更多相关文章

  1. 【转】Cowboy 开源 WebSocket 网络库

    原文链接: http://www.cnblogs.com/gaochundong/p/cowboy_websockets.html

  2. 我对开源C++网络库简单应用总结

    网上有篇文章<开源免费的C/C++网络库(c/c++ sockets library) 七剑下天山>,看了之后觉得每个库都不错,这里我具体下载这些库看一下,简单总结一下: 顺便添加一些我找 ...

  3. [开源] gnet: 一个轻量级且高性能的 Golang 网络库

    Github 主页 https://github.com/panjf2000/gnet 欢迎大家围观~~,目前还在持续更新,感兴趣的话可以 star 一下暗中观察哦. 简介 gnet 是一个基于 Ev ...

  4. go网络库cellent实现socket聊天功能

    一 .介绍 cellnet是一个组件化.高扩展性.高性能的开源服务器网络库 git地址:https://github.com/davyxu/cellnet 主要使用领域: 游戏服务器 方便定制私有协议 ...

  5. boost.ASIO-可能是下一代C++标准的网络库

    曾几何时,Boost中有一个Socket库,但后来没有了下文,C++社区一直在翘首盼望一个标准网络库的出现,网络上开源的网络库也有不少,例如Apache Portable Runtime就是比较著名的 ...

  6. muduo 网络库学习之路(一)

    前提介绍: 本人是一名大三学生,主要使用C++开发,兴趣是高性能的服务器方面. 网络开发离不开网络库,所以今天开始学一个新的网络库,陈老师的muduo库 我参考的书籍就是陈老师自己关于muduo而编著 ...

  7. MTNET 自用ios网络库开源

    短短两天就在https://git.oschina.net/gangwang/MTNET这里收获15个星 github 5星, 值得收藏! MTNET 自用ios网络库开源, 自用很久了,在数歀上架的 ...

  8. 开源免费的C/C++网络库(c/c++ sockets library)

    (1)ACE 庞大.复杂,适合大型项目.开源.免费,不依赖第三方库,支持跨平台. http://www.cs.wustl.edu/~schmidt/ACE.html (2)Asio Asio基于Boo ...

  9. 【转】开源C/C++网络库比较

    在开源的C/C++网络库中, 常用的就那么几个, 在业界知名度最高的, 应该是ACE了, 不过是个重量级的大家伙, 轻量级的有libevent, libev, 还有 Boost的ASIO. ACE是一 ...

随机推荐

  1. CSS3 background-image背景图片相关介绍

    这里将会介绍如何通过background-image设置背景图片,以及背景图片的平铺.拉伸.偏移.设置大小等操作. 1. 背景图片样式分类 CSS中设置元素背景图片及其背景图片样式的属性主要以下几个: ...

  2. [C#] C# 基础回顾 - 匿名方法

    C# 基础回顾 - 匿名方法 目录 简介 匿名方法的参数使用范围 委托示例 简介 在 C# 2.0 之前的版本中,我们创建委托的唯一形式 -- 命名方法. 而 C# 2.0 -- 引进了匿名方法,在 ...

  3. C++实现线程安全的单例模式

    在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式.单例模式分为懒汉模式,跟饿汉模式两种. 首先给出饿汉模式的实现 template <class T> class sing ...

  4. 基于netty http协议栈的轻量级流程控制组件的实现

    今儿个是冬至,所谓“冬大过年”,公司也应景五点钟就放大伙儿回家吃饺子喝羊肉汤了,而我本着极高的职业素养依然坚持留在公司(实则因为没饺子吃没羊肉汤喝,只能呆公司吃食堂……).趁着这一个多小时的时间,想跟 ...

  5. 微信开发 :WeixinPayInfoCollection尚未注册Mch 问题解决

    在使用开源项目 SENPARC.WEIXIN SDK 调用微信支付接口的时候出现了WeixinPayInfoCollection尚未注册Mch,这个问题. 最后地解决方案是: 我这个傻逼忘了在全局Gl ...

  6. C# 自定义控件VS用户控件

    1 自定义控件与用户控件区别 WinForm中, 用户控件(User Control):继承自 UserControl,主要用于开发 Container 控件,Container控件可以添加其他Con ...

  7. JQuery中的siblings()是什么意思

    jQuery siblings() 方法返回被选元素的所有同胞元素,并且可以使用可选参数来过滤对同胞元素的搜索. 实例演示:点击某个li标签后将其设置为红色,而其所有同胞元素去除红色样式. 1.创建H ...

  8. ObserverPattern(观察者模式)

    import java.util.ArrayList; import java.util.List; /** * 观察者模式 * @author TMAC-J * 牵一发而动全身来形容观察者模式在合适 ...

  9. CSS入门常见的问题

    写在前面:本文简单介绍一下css的三大特性:层叠性.继承性.优先级.以及margin,padding,浮动,定位几个知识点.限于水平,不深入探讨,仅作为学习总结. 1,三特性 1)层叠性:同标签同权重 ...

  10. Visual Studio 2013 添加一般应用程序(.ashx)文件到SharePoint项目

    默认,在用vs2013开发SharePoint项目时,vs没有提供一般应用程序(.ashx)的项目模板,本文解决此问题. 以管理员身份启动vs2013,创建一个"SharePoint 201 ...