DotNetty介绍
DotNetty是微软的Azure团队,使用C#实现的Netty
的版本发布。不但使用了C#和.Net平台的技术特点,并且保留了Netty
原来绝大部分的编程接口。让我们在使用时,完全可以依照Netty
官方的教程来学习和使用DotNetty应用程序。
dotNetty 是一个非阻塞、事件驱动的网络框架。dotNetty 实际上是使用 Threads(多线程)处理 I/O 事件,DotNetty
是一个NIO
客户端服务端框架,它使得快速而简单的开发像服务端客户端协议的网络应用成为了可能。它极大的简化并流线化了如TCP
和UDP
套接字服务器开发的网络编程。dotNetty
成功找到了一个无需折衷妥协而让开发、性能、稳定性和灵活性相互协调的方法。
类库简介
- DotNetty.Buffers
- 对内存缓冲区管理的封装。
- DotNetty.Codecs
- 对编解码是封装,包括一些基础基类的实现,在项目中自定义的协议,都要继承该项目的特定基类和实现。
- DotNetty.Codecs.Mqtt
MQTT
(消息队列遥测传输)编解码是封装,包括一些基础基类的实现。
- DotNetty.Codecs.Protobuf
Protobuf
编解码是封装,包括一些基础基类的实现。
- DotNetty.Codecs.ProtocolBuffers
ProtocolBuffers
编解码是封装,包括一些基础基类的实现。
- DotNetty.Codecs.Redis
Redis
协议编解码是封装,包括一些基础基类的实现。
- DotNetty.Common
- 是公共的类库项目,包装线程池,并行任务和常用帮助类的封装。
- DotNetty.Handlers
- 封装了常用的管道处理器,比如
Tls
编解码,超时机制,心跳检查,日志等。
- 封装了常用的管道处理器,比如
- DotNetty.Transport
- 是
DotNetty
核心的实现,Socket
基础框架,通信模式:异步非阻塞。
- 是
- DotNetty.Transport.Libuv
- 是
DotNetty
自己实现基于Libuv
(高性能的,事件驱动的I/O库) 核心的实现。
- 是
架构图
DotNetty核心概念
BOOTSTRAP
DotNetty
应用程序通过设置 Bootstrap
(引导)类的开始,该类提供了一个用于应用程序网络层配置的容器。
CHANNEL
底层网络传输API必须提供给应用 I/O操作的接口,如读,写,连接,绑定等等。对于我们来说,这是结构几乎总是会成为一个“socket”。DotNetty
中的接口Channel
定义了与 socket 丰富交互的操作集:bind
, close
, config
, connect
, isActive
, isOpen
, isWritable
, read
, write
等等。 DotNetty
提供大量的 Channel
实现来专门使用。这些包括 AbstractChannel
,AbstractNioByteChannel
,AbstractNioChannel
,EmbeddedChannel
, LocalServerChannel
,NioSocketChannel
等等。
CHANNELHANDLER
ChannelHandler
支持很多协议,并且提供用于数据处理的容器。我们已经知道ChannelHandler
由特定事件触发。 ChannelHandler
可专用于几乎所有的动作,包括将一个对象转为字节(或相反),执行过程中抛出的异常处理。
常用的一个接口是 ChannelInboundHandler
,这个类型接收到入站事件(包括接收到的数据)可以处理应用程序逻辑。当你需要提供响应时,你也可以从 ChannelInboundHandler
冲刷数据。一句话,业务逻辑经常存活于一个或者多个 ChannelInboundHandler
。
CHANNELPIPELINE
ChannelPipeline
提供了一个容器给 ChannelHandler
链并提供了一个API 用于管理沿着链入站和出站事件的流动。每个 Channel
都有自己的ChannelPipeline
,当Channel
创建时自动创建的。 ChannelHandler
是如何安装在 ChannelPipeline
? 主要是实现了ChannelHandler
的抽象 ChannelInitializer
。ChannelInitializer
子类 通过 ServerBootstrap
进行注册。当它的方法 InitChannel()
被调用时,这个对象将安装自定义的 ChannelHandler
集到 pipeline
。当这个操作完成时,ChannelInitializer
子类则 从 ChannelPipeline
自动删除自身。
EVENTLOOP
EventLoop
用于处理 Channel
的 I/O 操作。一个单一的 EventLoop
通常会处理多个 Channel
事件。一个 EventLoopGroup
可以含有多于一个的EventLoop
和 提供了一种迭代用于检索清单中的下一个。
CHANNELFUTURE
DotNetty
所有的 I/O 操作都是异步。因为一个操作可能无法立即返回,我们需要有一种方法在以后确定它的结果。出于这个目的,dotNetty 提供了接口 ChannelFuture
,它的 AddListener
方法注册了一个 ChannelFutureListener
,当操作完成时,可以被通知(不管成功与否)。
引导
Bootstrap 类型
DotNetty
的包括两种不同类型的引导。 两个引导实现自一个名为AbstractBootstrap
的超类。
服务端引导
“服务器”应用程序把一个“父”管道接受连接和创建“子”管道,ServerBootstrap
中的 ChildHandler()
, ChildAttr()
和 ChildOption()
是常用的服务器应用的操作。具体来说,ServerChannel
实现负责创建子 Channel
,它代表接受连接。因此 引导 ServerChannel
的 ServerBootstrap
,提供这些方法来简化接收的 Channel
对 ChannelConfig
应用设置的任务。
下图展示了服务端是如何工作的
1 | // 主工作线程组,设置为1个线程 |
- 创建要给新的
ServerBootstrap
来创建新的SocketChannel
管道并绑定他们 - 指定
EventLoopGroup
用于从注册的ServerChannel
中获取EventLoop
和接收到的管道 - 指定要使用的管道类
- 设置子处理器用于处理接收的管道的 I/O 和数据
- 通过配置引导来绑定管道
客户端引导
“客户端”很可能只需要一个单一的、非“父”对所有网络交互的管道。
- 如何引导客户端?
Bootstrap
类负责创建管道给客户或应用程序,利用无连接协议和在调用Bind()
或Connect()
之后。
下图展示了如何工作1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32var group = new MultithreadEventLoopGroup();
X509Certificate2 cert = null;
string targetHost = null;
if (ClientSettings.IsSsl)
{
cert = new X509Certificate2(Path.Combine(ExampleHelper.ProcessDirectory, "dotnetty.com.pfx"), "password");
targetHost = cert.GetNameInfo(X509NameType.DnsName, false);
}
var bootstrap = new Bootstrap();
bootstrap
.Group(group)
.Channel<TcpSocketChannel>()
.Option(ChannelOption.TcpNodelay, true)
.Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
{
IChannelPipeline pipeline = channel.Pipeline;
if (cert != null)
{
pipeline.AddLast("tls", new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), new ClientTlsSettings(targetHost)));
}
pipeline.AddLast(new LoggingHandler());
pipeline.AddLast("framing-enc", new LengthFieldPrepender(2));
pipeline.AddLast("framing-dec", new LengthFieldBasedFrameDecoder(ushort.MaxValue, 0, 2, 0, 2));
pipeline.AddLast("echo", new EchoClientHandler());
}));
IChannel clientChannel = await bootstrap.ConnectAsync(new IPEndPoint(ClientSettings.Host, ClientSettings.Port));
await clientChannel.CloseAsync();
- 创建一个新的 Bootstrap 来创建和连接到新的客户端管道
- 指定 EventLoopGroup
- 指定 Channel 实现来使用
- 设置处理器给 Channel 的事件和数据
- 连接到远端主机