Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的高性能客户端/服务器 通讯框架。
Netty的优势:
- 并发高
- 传输快
- 封装好
还有一个叫做 内存零拷贝技术。
整体架构大致如下图:
从架构图来看,NIO非阻塞模型的连接数要多许多。
DotNetty
然而,我是偏向.Net技术栈的,所以,我采用DotNetty来使用Netty技术实现通讯的高性能,我也抽时间对里面的细节做了研究,但是,针对于内存零拷贝技术(DMA 内存直接访问),Windows平台好像没有相应的接口,所以,也不了了之,有知道的大佬,也可以告诉我,不吝感激。
实际项目
分为服务端和客户端
服务端 Server
先安装Nuget包
Install-Package DotNetty.Codecs -Version 0.7.2
Install-Package DotNetty.Transport -Version 0.7.2
然后,实现服务端代码,用第三方就是方便,几行代码就搞定了。
NettyServer.cs
/// <summary>
/// 服务
/// </summary>
public class NettyServer
{
public async Task Listen(int port)
{
var boos = new MultithreadEventLoopGroup(1);
var work = new MultithreadEventLoopGroup();
var bootstrap = new ServerBootstrap();
bootstrap.Group(boos, work)
.Channel<TcpServerSocketChannel>()
.Option(ChannelOption.SoBacklog, 100)
.ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel => {
IChannelPipeline pipeline = channel.Pipeline;
pipeline.AddLast(new ServerMessageHandler());
}));
IChannel boundChannel = await bootstrap.BindAsync(port);
}
}
ServerMessageHandler.cs
实现具体的业务
public class ServerMessageHandler : ChannelHandlerAdapter
{
public override void ChannelRead(IChannelHandlerContext context, object message)
{
var buffer = message as IByteBuffer;
if (buffer != null)
{
string receiveData = buffer.ToString(Encoding.UTF8);
Console.WriteLine("服务端获取到:" + receiveData);
byte[] messageBytes = Encoding.UTF8.GetBytes(receiveData);
IByteBuffer byteBuffer = Unpooled.Buffer(256);
byteBuffer.WriteBytes(messageBytes);
context.WriteAndFlushAsync(byteBuffer);
}
}
public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush();
public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
{
context.CloseAsync();
}
}
测试运行代码
static void Main(string[] args)
{
var server = new NettyServer();
server.Listen(9999).Wait();
Console.WriteLine("服务启动");
Console.ReadLine();
}
客户端实现 Client
来先安装Nuget包
Install-Package DotNetty.Codecs -Version 0.7.2
Install-Package DotNetty.Handlers -Version 0.7.2
Install-Package DotNetty.Transport -Version 0.7.2
客户端实现 NettyClinet.cs
/// <summary>
/// 客户端
/// </summary>
public class NettyClinet
{
public static IChannel Channel { set; get; }
public static IEventLoopGroup Group { set; get; }
public static ClientMessageHandler clientMessageHandler = new ClientMessageHandler();
public async void Connect(string host, int port)
{
Group = new MultithreadEventLoopGroup();
var bootstrap = new Bootstrap();
bootstrap
.Group(Group)
.Channel<TcpSocketChannel>()
.Option(ChannelOption.TcpNodelay, true)
.Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
{
IChannelPipeline pipeline = channel.Pipeline;
pipeline.AddLast(clientMessageHandler);
}));
Channel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(host), port));
}
public async void Close()
{
await Channel.CloseAsync();
await Group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1));
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
public bool SendMessage(string message)
{
if (message == null)
{
return false;
}
IByteBuffer buffer = Unpooled.Buffer(256);
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
buffer.WriteBytes(messageBytes);
Channel.WriteAndFlushAsync(buffer);
return true;
}
}
ClientMessageHandler.cs
实现客户端读取数据的业务
public class ClientMessageHandler : ChannelHandlerAdapter
{
public override void ChannelRead(IChannelHandlerContext context, object message)
{
var byteBuffer = message as IByteBuffer;
if (byteBuffer != null)
{
var data = byteBuffer.ToString(Encoding.UTF8);
Console.WriteLine("客户端收到:" + data);
}
}
public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush();
public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
{
Console.WriteLine("Exception: " + exception);
context.CloseAsync();
}
} public class ClientMessageHandler : ChannelHandlerAdapter
{
public override void ChannelRead(IChannelHandlerContext context, object message)
{
var byteBuffer = message as IByteBuffer;
if (byteBuffer != null)
{
var data = byteBuffer.ToString(Encoding.UTF8);
Console.WriteLine("客户端收到:" + data);
}
}
public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush();
public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
{
Console.WriteLine("Exception: " + exception);
context.CloseAsync();
}
}
客户端测试
static void Main(string[] args)
{
var clinet = new NettyClinet();
clinet.Connect("127.0.0.1", 9999);
Console.WriteLine("客户端开始连接!");
string content = "";
while (!(content = Console.ReadLine()).Contains("Exit", StringComparison.InvariantCultureIgnoreCase))
{
clinet.SendMessage(content);
}
Console.ReadLine();
}
至此,已经把Netty的服务端与客户端写完了。
来看下效果
Netty 通讯效果
先启动服务端,然后,再启动客户端
我们看下效果
效果还是很明显的
总结
基于Netty高性能的通讯框架搭建好了,也测试了。至此,已经对大多数通讯有了大致的了解,更加深入的知识点,还需要看文档,看源码,以及有针对性的解决了。
代码地址
https://github.com/kesshei/NettyDemo.git
https://gitee.com/kesshei/NettyDemo.git