到目前為止,我們上面幾篇教學中的所有例子都使用ByteBuf作為協定訊息的主要資料結構。 在本節中,我們將改進TIME協定的用戶端和伺服器範例,讓它們使用POJO來代替原來的ByteBuf。
在ChannelHandler
中使用POJO的優點是顯而易見的; 處理程式將從ByteBuf中提取資訊的程式碼,將從處理程式中分離出來,變得更易維護和可重用。 在TIME用戶端和伺服器範例中,我們唯讀取一個32位元整數,它不是直接使用ByteBuf來解碼轉換的。在實現真實世界協定時,這是必須要進行分離的。
首先,我們定義一個名為 UnixTime
的新型別(一個簡單的Java類)。
package com.yiibai.netty.timepojo;
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() {
Date date = new Date((value() - 2208988800L) * 1000L);
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(date);
return dateString;
}
}
我們現在來修改時間解碼器(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
的實現,是將UnixTime
轉換回ByteBuf
。 它比編寫解碼器簡單得多,因為在編碼訊息時不需要處理資料包分段和組合。
package com.yiibai.netty.timepojo;
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 flush(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());
}
}
剩下的最後一個任務是在TimeServerHandler
之前將TimeEncoder
插入到伺服器端的ChannelPipeline
中,這裡將留作一個簡單的練習吧。
參考程式碼: Netty->NettyTutorial->com.yiibai.netty.pojo
;