本篇文章主要介绍如何快速学习、认识Netty,你也可以把它理解为 学习介绍
、快速入门
。强烈建议你收藏此篇文章,方便后续查阅。
Netty
netty 是一个基于 NIO
模型,实现的 高性能
、弹性
、可拓展性
的 异步事件驱动
网络
应用程序框架。你可以使用她快速
开发 稳定
、灵活
的 客户端
、服务端
应用。官方介绍请看 here 。
体系结构
在入手之前,我们先来看看技术的整体架构(不喜欢此节,你可以直接跳过去 [get start])
netty 体系结构
核心组件
这里会列出netty核心组件,当然由于篇幅问题不会做过多讲解
ByteBuf
io.netty.buffer.ByteBuf
是 netty 自定义的二进制数据存储组件,功能类似 java.nio.ByteBuffer
,但是它更加简化用户的使用。
readerIndex & writerIndex
如图所示,ByteBuf 定义了readerIndex & writerIndex 方便我们对ByteBuf读取与写入。
CompositeByteBuf
CompositeByteBuf
是虚拟的buffer,将多个buffer展现为一个简单合并的buffer。这个在多Buffer需要合成一个Buffer情况下使用时(减少内存拷贝)非常实用。
Channel
io.netty.channel
连接到网络套接字或能够进行读、写、连接和绑定等I/O操作的组件。
常用实现类
- NioSocketChannel 客户端 NIO selector 实现
- NioServerSocketChannel 服务端 NIO selector 实现
ChannelPipeline
io.netty.channel.ChannelPipeline
责任链( ChannelHandler List)模式设计,用于处理或拦截Channel的入站事件和出站操作。处理顺序如下:
ChannelHandler
io.netty.channel.ChannelHandler
IO事件处理器,这是我们使用最频繁的接口,为了实现我们自己的业务逻辑我们必须向pipeline
中添加自己的处理器。
ChannelHandler 入站 & 出站处理
ChannelInboundHandler
入站处理,在使用过程中一般使用ChannelInboundHandlerAdapter
适配类ChannelOutboundHandler
出站处理,在使用过程中一般使用ChannelOutboundHandlerAdapter
适配类
EventLoop
io.netty.channel.EventLoop
负责处理一个或者多个 Channel
,每一个EventLoop
都会绑定一个 Thread
。
我们常用的是 NioEventLoopGroup
,其是 EventLoopGroup
实现类,NIO
模型中的 EventLoop
集合。
Getting Started
终于到这一节了,这一小节会写一个简单的DEMO。相关说明也在代码里加了注释。更加详细说明可以参考 here
Echo Server
public class NettyEchoServerDemo {
public static void main(String[] args) throws Exception {
//多线程事件处理器,默认当前核心数 * 2
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//启动类
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)// nio socketchannel
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
//添加应用,数据处理程序 ChannelHandler
ch.pipeline().addLast(new EchoChannelHandler());
}
})
//option 用于设置NioServerSocketChannel
.option(ChannelOption.SO_BACKLOG, 128)
//childOption 用于设置获取到的Channel 也就是 NioSocketChannel
.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(7).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
//自定义一个 ChannelInboundHandler
public static class EchoChannelHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.write(msg);
ctx.flush();
}
}
}
复制代码
Echo Client
public class NettyEchoClientDemo {
public static void main(String[] args) throws Exception {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//client 启动类
Bootstrap b = new Bootstrap();
b.group(workerGroup)
//SocketChannel
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() { // (4)
@Override
public void initChannel(SocketChannel ch) throws Exception {
//自定义数据处理程序 ChannelHandler
ch.pipeline().addLast(new EchoChannelHandler());
}
})
.option(ChannelOption.SO_KEEPALIVE, true);
//建立连接
ChannelFuture f = b.connect("127.0.0.1",7).syncUninterruptibly(); // (7)
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
}
//自定义 ChannelInboundHandler
public static class EchoChannelHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(((ByteBuf)msg).toString(CharsetUtil.UTF_8));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
//与服务端交互
String name = bufferedReader.readLine();
System.out.println(name);
ctx.writeAndFlush(Unpooled.copiedBuffer(name.getBytes()));
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
//首次出发,发送消息给服务端 这里需要传 ByteBuf
ChannelFuture c = ctx.writeAndFlush(Unpooled.copiedBuffer("message".getBytes()));
if(!c.isSuccess()){
System.out.println(c.cause());
}
}
}
}
复制代码
感谢