长久以来,.Net开发人员都非常羡慕Java有Netty这样,高效,稳定又易用的网络通信基础框架。终于微软的Azure团队,使用C#实现的Netty的版本发布。不但使用了C#和.Net平台的技术特点,并且保留了Netty原来绝大部分的编程接口。让我们在使用时,完全可以依照Netty官方的教程来学习和使用DotNetty应用程序。
DotNetty同时也是开源的,它的源代码托管在Github上:https://github.com/azure/dotnetty
0x01 项目预览
从github上下载最新的代码到本地,使用VS2017或者VSCode打开下载好的代码,可以看到如图所示的代码那结构,其中源码部分有9个项目组成,其中
DotNetty.Common 是公共的类库项目,包装线程池,并行任务和常用帮助类的封装
DotNetty.Transport 是DotNetty核心的实现
DotNetty.Buffers 是对内存缓冲区管理的封装
DotNetty.Codes 是对编解码是封装,包括一些基础基类的实现,我们在项目中自定义的协议,都要继承该项目的特定基类和实现
DotNetty.Handlers 封装了常用的管道处理器,比如Tls编解码,超时机制,心跳检查,日志等,如果项目中没有用到可以不引用,不过一般都会用到
其他还有对Redis的编解码,Mqtt的编解码,Protobuf2/3的编解码项目中可根据实际情况引用
很遗憾Http协议和Websocket协议还没有实现。
0x02 快速开始-示例-回声程序的实现
从上一步下载的代码中,看到有一个sample目录,有很多例子,都大同小异, 先来看这个最简单的Echo服务的实现吧.
Echo服务,分为服务端和客户端,服务端使用DotNetty框架启动一个Socket服务,并等待客户端链接,当客户端链接并接收客户端消息,并将接收到的消息原样返回给客户端。而客户端同样使用DotNetty框架启动一个Socket客户端服务,并链接到服务端,并发送一条Hello的字符串信息,并等待服务端返回。如此往复。
2.1 Echo Server
来一起看一下代码吧,我把注释都写到代码中:
static async Task RunServerAsync(){
//设置输出日志到Console
ExampleHelper.SetConsoleLogger();
// 主工作线程组,设置为1个线程
var bossGroup = new MultithreadEventLoopGroup(1);
// 工作线程组,默认为内核数*2的线程数
var workerGroup = new MultithreadEventLoopGroup();
X509Certificate2 tlsCertificate = null;
if (ServerSettings.IsSsl) //如果使用加密通道
{
tlsCertificate = new X509Certificate2(Path.Combine(ExampleHelper.ProcessDirectory, "dotnetty.com.pfx"), "password");
} try
{
//声明一个服务端Bootstrap,每个Netty服务端程序,都由ServerBootstrap控制,
//通过链式的方式组装需要的参数
var bootstrap = new ServerBootstrap();
bootstrap
.Group(bossGroup, workerGroup) // 设置主和工作线程组
.Channel<TcpServerSocketChannel>() // 设置通道模式为TcpSocket
.Option(ChannelOption.SoBacklog, 100) // 设置网络IO参数等,这里可以设置很多参数,当然你对网络调优和参数设置非常了解的话,你可以设置,或者就用默认参数吧
.Handler(new LoggingHandler("SRV-LSTN")) //在主线程组上设置一个打印日志的处理器
.ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel =>
{ //工作线程连接器 是设置了一个管道,服务端主线程所有接收到的信息都会通过这个管道一层层往下传输//同时所有出栈的消息 也要这个管道的所有处理器进行一步步处理
IChannelPipeline pipeline = channel.Pipeline; if (tlsCertificate != null) //Tls的加解密
{
pipeline.AddLast("tls", TlsHandler.Server(tlsCertificate));
} //日志拦截器
pipeline.AddLast(new LoggingHandler("SRV-CONN"));//出栈消息,通过这个handler 在消息顶部加上消息的长度