这是我参与更文挑战的第 17 天,活动详情查看
theme: channing-cyan highlight: a11y-dark
到目前为止,我们回顾的所有示例都使用 一个ByteBuf作为协议消息的主要数据结构。在本节中,我们将改进TIME协议客户端和服务器示例以使用 POJO 而不是ByteBuf.
在你的ChannelHandlers中使用 POJO 的优势是显而易见的;通过分离ByteBuf从处理程序中提取信息的代码,您的处理程序变得更易于维护和重用。在TIME客户端和服务器示例中,我们只读取一个 32 位整数,ByteBuf直接使用不是主要问题。但是,您会发现在实现实际协议时有必要进行分离。
首先,让我们定义一个名为 的新类型UnixTime。
package io.netty.example.time;
import java.util.Date;
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();
}
}
我们现在可以修改TimeDecoder以生成 UnixTime而不是ByteBuf
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
if (in.readableBytes() < 4) {
return;
}
out.add(new UnixTime(in.readUnsignedInt()));
}
使用更新的解码器,TimeClientHandler不再使用ByteBuf:
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
UnixTime m = (UnixTime) msg;
System.out.println(m);
ctx.close();
}
更简单和优雅,对吧?可以在服务器端应用相同的技术。TimeServerHandler这次我们先更新一下:
@Override
public void channelActive(ChannelHandlerContext ctx) {
ChannelFuture f = ctx.writeAndFlush(new UnixTime());
f.addListener(ChannelFutureListener.CLOSE);
}
现在,唯一缺少的部分是编码器,它是ChannelOutboundHandler将 aUnixTime转换为ByteBuf. 它比编写解码器简单得多,因为在编码消息时无需处理数据包碎片和组装。
package io.netty.example.time;
public class TimeEncoder extends ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
UnixTime m = (UnixTime) msg;
ByteBuf encoded = ctx.alloc().buffer(4);
encoded.writeInt((int)m.value());
ctx.write(encoded, promise); // (1)
}
}
在这一行中有很多重要的事情。
- 首先,我们按原样传递原始数据ChannelPromise,以便 Netty 在编码数据实际写入线路时将其标记为成功或失败。
- 其次,我们没有调用ctx.flush(). 有一个单独的处理程序方法void lush(ChannelHandlerContext ctx)用于覆盖flush()操作。
为了进一步简化,您可以使用MessageToByteEncoder:
public class TimeEncoder extends MessageToByteEncoder<UnixTime> {
@Override
protected void encode(ChannelHandlerContext ctx, UnixTime msg, ByteBuf out) {
out.writeInt((int)msg.value());
}
}
剩下的最后一个任务是插入TimeEncoder到ChannelPipeline之前的服务器端TimeServerHandler,并留作一件容易的事。
关闭您的应用程序 关闭 Netty 应用程序通常就像关闭EventLoopGroup您通过shutdownGracefully(). Future当sEventLoopGroup已完全终止并且Channel属于该组的所有s 已关闭时,它会返回通知您。