@[TOC]netty实战
1. 背景
Netty使用有一段时间了,在项目生产环境中也得以实践,最近想回炉温故一下理论,健全自己的知识体系,怕时间长了遗忘,在此做个笔记。
2. 整体认识
2.1 定义
Netty提供异步的、事件驱动的网络应用程序框架和工具,可
以快速开发高性能、高可靠的网络服务器和客户端程序。
异步:我理解为不用等待。
事件驱动:我理解为读或写操作。
2.2 示例
编写一个简单的服务,客户端发送一个英文字符到服务端,服务端立马返回。
- netty版本
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.55.Final</version>
</dependency>
- 自定义handler
public class FirstHandler extends ChannelInboundHandlerAdapter {
public static final Logger log = LoggerFactory.getLogger(FirstHandler.class);
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.info("服务端接收消息是:{}", msg);
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
}
- 定义server
public class FirstServer {
public static final Logger log = LoggerFactory.getLogger(FirstServer.class);
private final String ip = "127.0.0.1";
private final String port = "8001";
public void init(){
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bs = new ServerBootstrap();
bs.group(bossGroup, workerGroup);
bs.channel(NioServerSocketChannel.class);
bs.childHandler(new ChannelInitializer<Channel>(){
@Override
protected void initChannel(Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LoggingHandler(LogLevel.INFO));
pipeline.addLast(new FirstHandler());
}
});
try {
ChannelFuture channelFuture = bs.bind(ip, Integer.parseInt(port)).sync();
log.info("Netty Server 启动成功! Ip: " + channelFuture.channel().localAddress().toString() + " ! ");;
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2.3 事件分析
启动上述服务端程序后,在命令行使用telnet 127.0.0.1 8001进行测试。操作如下:
- 打开命令行窗口后,输入telnet 127.0.0.1 8001回车,日志如下:
11:44:39.676 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x05468150, L:/127.0.0.1:8001 - R:/127.0.0.1:8469] REGISTERED
11:44:39.676 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x05468150, L:/127.0.0.1:8001 - R:/127.0.0.1:8469] ACTIVE
- 在命令行输入字符a
11:46:33.471 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x05468150, L:/127.0.0.1:8001 - R:/127.0.0.1:8469] READ: 1B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 61 |a |
+--------+-------------------------------------------------+----------------+
11:46:33.472 [nioEventLoopGroup-3-1] INFO com.wniu.handler.FirstHandler - 服务端接收消息是:PooledUnsafeDirectByteBuf(ridx: 0, widx: 1, cap: 2048)
11:46:33.472 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x05468150, L:/127.0.0.1:8001 - R:/127.0.0.1:8469] WRITE: 1B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 61 |a |
+--------+-------------------------------------------------+----------------+
11:46:33.475 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x05468150, L:/127.0.0.1:8001 - R:/127.0.0.1:8469] READ COMPLETE
11:46:33.475 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x05468150, L:/127.0.0.1:8001 - R:/127.0.0.1:8469] FLUSH
- 关闭命令行窗口
11:48:58.595 [nioEventLoopGroup-3-2] INFO io.netty.handler.logging.LoggingHandler - [id: 0x4655d9ba, L:/127.0.0.1:8001 - R:/127.0.0.1:3761] READ COMPLETE
11:48:58.595 [nioEventLoopGroup-3-2] INFO io.netty.handler.logging.LoggingHandler - [id: 0x4655d9ba, L:/127.0.0.1:8001 - R:/127.0.0.1:3761] FLUSH
11:48:58.595 [nioEventLoopGroup-3-2] INFO io.netty.handler.logging.LoggingHandler - [id: 0x4655d9ba, L:/127.0.0.1:8001 ! R:/127.0.0.1:3761] INACTIVE
11:48:58.596 [nioEventLoopGroup-3-2] INFO io.netty.handler.logging.LoggingHandler - [id: 0x4655d9ba, L:/127.0.0.1:8001 ! R:/127.0.0.1:3761] UNREGISTERED
- 事件状态变换流程
REGISTERED:Channel注册
ACTIVE:Channel激活
READ:从当前Channel读取消息
READ COMPLETE:消息读取完成
FLUSH:消息读取完成后发送
INACTIVE:Channel结束生命周期
UNREGISTERED:Channel注销
2.4 扩展
日志中打印a字符的ascii码值61(十六进制),如果传送中文消息将会怎样,是不是需要添加handler进行解码?下章进行验证。