日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

netty系列之:使用POJO替代buf

發(fā)布時間:2024/2/28 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 netty系列之:使用POJO替代buf 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 簡介
  • decode和encode
  • 對象序列化
  • 使用編碼和解碼器
  • 總結(jié)

簡介

在之前的文章中我們提到了,對于NioSocketChannel來說,它不接收最基本的string消息,只接收ByteBuf和FileRegion。但是ByteBuf是以二進(jìn)制的形式進(jìn)行處理的,對于程序員來說太不直觀了,處理起來也比較麻煩,有沒有可能直接處理java簡單對象呢?本文將會探討一下這個問題。

decode和encode

比如我們需要直接向channel中寫入一個字符串,在之前的文章中,我們知道這是不可以的,會報下面的錯誤:

DefaultChannelPromise@57f5c075(failure: java.lang.UnsupportedOperationException: unsupported message type: String (expected: ByteBuf, FileRegion))

也就說ChannelPromise只接受ByteBuf和FileRegion,那么怎么做呢?

既然ChannelPromise只接受ByteBuf和FileRegion,那么我們就需要把String對象轉(zhuǎn)換成ByteBuf即可。

也就是說在寫入String之前把String轉(zhuǎn)換成ByteBuf,當(dāng)要讀取數(shù)據(jù)的時候,再把ByteBuf轉(zhuǎn)換成String。

我們知道ChannelPipeline中可以添加多個handler,并且控制這些handler的順序。

那么我們的思路就出來了,在ChannelPipeline中添加一個encode,用于數(shù)據(jù)寫入的是對數(shù)據(jù)進(jìn)行編碼成ByteBuf,然后再添加一個decode,用于在數(shù)據(jù)寫出的時候?qū)?shù)據(jù)進(jìn)行解碼成對應(yīng)的對象。

encode,decode是不是很熟悉?對了,這就是對象的序列化。

對象序列化

netty中對象序列化是要把傳輸?shù)膶ο蠛虰yteBuf直接互相轉(zhuǎn)換,當(dāng)然我們可以自己實現(xiàn)這個轉(zhuǎn)換對象。但是netty已經(jīng)為我們提供了方便的兩個轉(zhuǎn)換類:ObjectEncoder和ObjectDecoder。

先看ObjectEncoder,他的作用就是將對象轉(zhuǎn)換成為ByteBuf。

這個類很簡單,我們對其分析一下:

public class ObjectEncoder extends MessageToByteEncoder<Serializable> {private static final byte[] LENGTH_PLACEHOLDER = new byte[4];@Overrideprotected void encode(ChannelHandlerContext ctx, Serializable msg, ByteBuf out) throws Exception {int startIdx = out.writerIndex();ByteBufOutputStream bout = new ByteBufOutputStream(out);ObjectOutputStream oout = null;try {bout.write(LENGTH_PLACEHOLDER);oout = new CompactObjectOutputStream(bout);oout.writeObject(msg);oout.flush();} finally {if (oout != null) {oout.close();} else {bout.close();}}int endIdx = out.writerIndex();out.setInt(startIdx, endIdx - startIdx - 4);} }

ObjectEncoder繼承了MessageToByteEncoder,而MessageToByteEncoder又繼承了ChannelOutboundHandlerAdapter。為什么是OutBound呢?這是因為我們是要對寫入的對象進(jìn)行轉(zhuǎn)換,所以是outbound。

首先使用ByteBufOutputStream對out ByteBuf進(jìn)行封裝,在bout中,首先寫入了一個LENGTH_PLACEHOLDER字段,用來表示stream中中Byte的長度。然后用一個CompactObjectOutputStream對bout進(jìn)行封裝,最后就可以用CompactObjectOutputStream寫入對象了。

對應(yīng)的,netty還有一個ObjectDecoder對象,用于將ByteBuf轉(zhuǎn)換成對應(yīng)的對象,ObjectDecoder繼承自LengthFieldBasedFrameDecoder,實際上他是一個ByteToMessageDecoder,也是一個ChannelInboundHandlerAdapter,用來對數(shù)據(jù)讀取進(jìn)行處理。

我們看下ObjectDecoder中最重要的decode方法:

protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {ByteBuf frame = (ByteBuf) super.decode(ctx, in);if (frame == null) {return null;}ObjectInputStream ois = new CompactObjectInputStream(new ByteBufInputStream(frame, true), classResolver);try {return ois.readObject();} finally {ois.close();}}

上面的代碼可以看到,將輸入的ByteBuf轉(zhuǎn)換為ByteBufInputStream,最后轉(zhuǎn)換成為CompactObjectInputStream,就可以直接讀取對象了。

使用編碼和解碼器

有了上面兩個編碼解碼器,直接需要將其添加到client和server端的ChannelPipeline中就可以了。

對于server端,其核心代碼如下:

//定義bossGroup和workerGroupEventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline();p.addLast(// 添加encoder和decodernew ObjectEncoder(),new ObjectDecoder(ClassResolvers.cacheDisabled(null)),new PojoServerHandler());}});// 綁定端口,并準(zhǔn)備接受連接b.bind(PORT).sync().channel().closeFuture().sync();

同樣的,對于client端,我們其核心代碼如下:

EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline();p.addLast(// 添加encoder和decodernew ObjectEncoder(),new ObjectDecoder(ClassResolvers.cacheDisabled(null)),new PojoClientHandler());}});// 建立連接b.connect(HOST, PORT).sync().channel().closeFuture().sync();

可以看到上面的邏輯就是將ObjectEncoder和ObjectDecoder添加到ChannelPipeline中即可。

最后,就可以在客戶端和瀏覽器端通過調(diào)用:

ctx.write("加油!");

直接寫入字符串對象了。

總結(jié)

有了ObjectEncoder和ObjectDecoder,我們就可以不用受限于ByteBuf了,程序的靈活程度得到了大幅提升。

本文的例子可以參考:learn-netty4

本文已收錄于 http://www.flydean.com/08-netty-pojo-buf/

最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發(fā)現(xiàn)!

歡迎關(guān)注我的公眾號:「程序那些事」,懂技術(shù),更懂你!

總結(jié)

以上是生活随笔為你收集整理的netty系列之:使用POJO替代buf的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。