溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于Protostuff怎么實現(xiàn)Netty編解碼器

發(fā)布時間:2022-03-23 10:52:35 來源:億速云 閱讀:147 作者:iii 欄目:web開發(fā)

本篇內容主要講解“基于Protostuff怎么實現(xiàn)Netty編解碼器”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“基于Protostuff怎么實現(xiàn)Netty編解碼器”吧!

  在設計netty的編解碼器過程中,有許多組件可以選擇,這里由于咱對Protostuff比較熟悉,所以就用這個組件了。由于數(shù)據(jù)要在網絡上傳輸,所以在發(fā)送方需要將類對象轉換成二進制,接收方接收到數(shù)據(jù)后,需要將二進制轉換成類對象。

  public class SerializeUtil {

  private static class SerializeData{

  private Object target;

  }

  @SuppressWarnings("unchecked")

  public static byte[] serialize(Object object) {

  SerializeData serializeData = new SerializeData();

  serializeData.target = object;

  Class<SerializeData> serializeDataClass = (Class<SerializeData>) serializeData.getClass();

  LinkedBuffer linkedBuffer = LinkedBuffer.allocate(1024 * 4);

  try {

  Schema<SerializeData> schema = RuntimeSchema.getSchema(serializeDataClass);

  return ProtostuffIOUtil.toByteArray(serializeData, schema, linkedBuffer);

  } catch (Exception e) {

  throw new IllegalStateException(e.getMessage(), e);

  } finally {

  linkedBuffer.clear();

  }

  }

  @SuppressWarnings("unchecked")

  public static <T> T deserialize(byte[] data, Class<T> clazz) {

  try {

  Schema<SerializeData> schema = RuntimeSchema.getSchema(SerializeData.class);

  SerializeData serializeData = schema.newMessage();

  ProtostuffIOUtil.mergeFrom(data, serializeData, schema);

  return (T) serializeData.target;

  } catch (Exception e) {

  throw new IllegalStateException(e.getMessage(), e);

  }

  }

  }

  但是,上面只是普通的操作Util,如何讓數(shù)據(jù)能夠在netty上進行傳輸呢?

  在netty中,如果想發(fā)送數(shù)據(jù)出去,那么需要將數(shù)據(jù)轉換成二進制,然后通過網絡傳送出去,他提供了MessageToByteEncoder的操作類,用戶需要繼承此類,然后實現(xiàn)encode方法就可以了。來看看我們如何將我們寫好的SerializeUtil操作類集成進去:

  public class NettyMessageEncoder extends MessageToByteEncoder<NettyMessage> {

  @Override

  protected void encode(ChannelHandlerContext ctx, NettyMessage msg, ByteBuf out) throws Exception {

  out.writeBytes(SerializeUtil.serialize(msg));

  }

  }

  如上代碼所示,我們就準備好了一個基于Protostuff組件實現(xiàn)的編碼類了。編碼后的數(shù)據(jù),被添加到ByteBuf緩沖區(qū)后,被發(fā)送出去。

  那么如何來實現(xiàn)解碼器呢?

  public class NettyMessageDecoder extends LengthFieldBasedFrameDecoder{

  public NettyMessageDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {

  super(maxFrameLength, lengthFieldOffset, lengthFieldLength);

  }

  @Override

  public  Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {

  try {

  byte[] dstBytes = new byte[in.readableBytes()];

  //in.getBytes(in.readerIndex(), dstBytes);

  //切記這里一定要用readBytes,不能用getBytes,否則會導致readIndex不能向后移動,從而導致netty did not read anything but decoded a message.錯誤

  in.readBytes(dstBytes,0,in.readableBytes());

  NettyMessage nettyMessage = SerializeUtil.deserialize(dstBytes, NettyMessage.class);

  return nettyMessage;

  } catch (Exception e) {

  System.out.println("exception when decoding: " + e);

  return null;

  }

  }

  }

  如上代碼所示。一般情況下,需要繼承netty中的ByteToMessageDecoder操作類來實現(xiàn),但是考慮到這樣的話需要用戶自己來處理粘包拆包問題,比較麻煩,所以我們就繼承自netty中為我們準備好的LengthFieldBasedFrameDecoder來進行,由于此decoder具有處理粘包拆包的功能,而且其繼承自ByteToMessageDecoder類,所以就省去了我們處理粘包拆包的邏輯。

  需要注意的是,在進行解碼的過程中,我們首先需要從緩沖區(qū)讀取數(shù)據(jù)到byte數(shù)組中,然后需要將readerIndex標記往后移動,如果讀完后不移動的話,會報netty did not read anything but decoded a message的錯誤,而且這個錯誤在你運行的時候并不會拋出來,非常隱蔽,要不是細細的調試客戶端,根本不能發(fā)覺此錯誤的存在。

  所以從上面代碼可以看出,ByteBuf.getBytes,只是單純的讀取緩存區(qū)數(shù)據(jù),并不會將readerIndex后移。但是ByteBuf.readBytes則會將readerIndex后移。這點必須重視。

  最后,我們將這兩個實現(xiàn)類放到handler執(zhí)行容器中即可。

  channel.pipeline()。addLast("nettyMessageDecoder", new NettyMessageDecoder(1024 * 1024, 4, 4));

  channel.pipeline()。addLast("nettyMessageEncoder", new NettyMessageEncoder());

  channel.pipeline()。addLast("readTimeoutHandler", new ReadTimeoutHandler(50));

  channel.pipeline()。addLast("loginAuthResponseHandler", new LoginAuthResponseHandler());

  channel.pipeline()。addLast("heartBeatHandler", new HeartBeatResponseHandler());

  最后啟動服務,我們就可以看到我們的編解碼器正常跑起來了:

  Login is ok: Netty Message [header=Header [crcCode=-1410399999,length=0,sessionId=0,type=4,priority=0,attachment={}]]

  Client send heart beat message to server : ----> Netty Message [header=Header [crcCode=-1410399999,length=0,sessionId=1344,type=5,priority=0,attachment={}]]

  Client receive server heartbeat message : ---> Netty Message [header=Header [crcCode=-1410

到此,相信大家對“基于Protostuff怎么實現(xiàn)Netty編解碼器”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI