情景导入
学习了前面的基础信息,我们发现我们的大部分内容都是基于 Bytebuf 去处理的。
对于 java 这一门 OO 的语言而言,我们更加习惯的是使用 Pojo 去处理。
代码示例
对象定义
- UnixTime.java
public class UnixTime {
private final long value;
public UnixTime() {
this(System.currentTimeMillis() / 1000L + 2208988800L);
}
public UnixTime(long value) {
this.value = value;
}
public long value() {
return value;
}
@Override
public String toString() {
return new Date((value() - 2208988800L) * 1000L).toString();
}
}
服务端
- PojoTimeServer.java
public class PojoTimeServer {
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
ChannelFuture channelFuture = serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeEncoder()).addLast(new PojoTimeServerHandler());
}
}).bind(8888)
.syncUninterruptibly();
channelFuture.channel().closeFuture().syncUninterruptibly();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
其中两个 handler 分别为:
- TimeEncoder.java
将对象转换为 Bybebuf
public class TimeEncoder extends MessageToByteEncoder<UnixTime> {
@Override
protected void encode(ChannelHandlerContext ctx, UnixTime msg, ByteBuf out) throws Exception {
// 对象序列化
long value = msg.value();
// 写入到 Bytebuf
out.writeLong(value);
}
}
- PojoTimeServerHandler.java
处理客户端 channel 链接时,发送时间到客户端。
public class PojoTimeServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// 字节写入时间戳
// 后续 encoder 会将其转换为 Bybebuf
ctx.writeAndFlush(new UnixTime());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客户端
- PojoTimeClient.java
public class PojoTimeClient {
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
ChannelFuture channelFuture = bootstrap.group(bossGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeDecoder()).addLast(new PojoTimeClientHandler());
}
})
.connect("localhost", 8888);
channelFuture.channel().closeFuture().syncUninterruptibly();
} finally {
bossGroup.shutdownGracefully();
}
}
}
其中 handler 如下:
- TimeDecoder.java
对时间戳进行解码为对象。
public class TimeDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// 将字节转化为对象
long value = in.readLong();
UnixTime unixTime = new UnixTime(value);
// 将对象输出到结果
out.add(unixTime);
}
}
- PojoTimeClientHandler.java
直接以对象的方式处理服务端信息。
public class PojoTimeClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
UnixTime unixTime = (UnixTime) msg;
System.out.println("Receive data from server: " + unixTime);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
个人感受
将转换和具体业务代码,使用 pipiline 的方式,可以提高复用率。
也可以使得代码变得简单专注。
实际使用
实际使用中,我们当然不会这么辛苦的去转换每一个对象。
直接结合 序列化框架概览 就可以非常简单的处理。
专业的事情交给专业的工具去处理。
拓展阅读
参考资料
《Netty 权威指南》