生活随笔
收集整理的這篇文章主要介紹了
Netty自定义协议
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、自定義協議要素
- 魔數,用來在第一時間判定是否是無效數據包,如java的coffee baby
- 版本號,可以支持協議的升級
- 序列化算法,消息正文到底采用哪種序列化反序列化方式,可以由此擴展,例如:json、protobuf、hessian、jdk
- 指令類型,是登錄、注冊、單聊、群聊… 跟業務相關
- 請求序號,為了雙工通信,提供異步能力
- 正文長度
- 消息正文:如json,xml
二、代碼
以下都是我們的自定義信息,我們希望對這些自定義信息類進行自定義編解碼操作,那么我們對他們的公共父類進行編解碼操作就可以。
自定義編解碼器
@Slf4j
public class MessageCodec extends ByteToMessageCodec<Message> {@Overridepublic void encode(ChannelHandlerContext ctx
, Message msg
, ByteBuf out
) throws Exception {out
.writeBytes(new byte[]{1, 2, 3, 4});out
.writeByte(1);out
.writeByte(0);out
.writeByte(msg
.getMessageType());out
.writeInt(msg
.getSequenceId());out
.writeByte(0xff);ByteArrayOutputStream bos
= new ByteArrayOutputStream();ObjectOutputStream oos
= new ObjectOutputStream(bos
);oos
.writeObject(msg
);byte[] bytes
= bos
.toByteArray();out
.writeInt(bytes
.length
);out
.writeBytes(bytes
);}@Overrideprotected void decode(ChannelHandlerContext ctx
, ByteBuf in
, List<Object> out
) throws Exception {int magicNum
= in
.readInt();byte version
= in
.readByte();byte serializerType
= in
.readByte();byte messageType
= in
.readByte();int sequenceId
= in
.readInt();in
.readByte();int length
= in
.readInt();byte[] bytes
= new byte[length
];in
.readBytes(bytes
, 0, length
);ObjectInputStream ois
= new ObjectInputStream(new ByteArrayInputStream(bytes
));Message message
= (Message) ois
.readObject();log
.debug("{}, {}, {}, {}, {}, {}", magicNum
, version
, serializerType
, messageType
, sequenceId
, length
);log
.debug("{}", message
);out
.add(message
);}
}
測試
public class TestMessageCodec {public static void main(String[] args
) throws Exception {EmbeddedChannel channel
= new EmbeddedChannel(new LoggingHandler(),new MessageCodec());LoginRequestMessage message
=new LoginRequestMessage("zhangsan","123");channel
.writeAndFlush(message
);}
}
- 測試半包現象(不添加 LengthFieldBasedFrameDecoder)
public class TestMessageCodec {public static void main(String[] args
) throws Exception {EmbeddedChannel channel
= new EmbeddedChannel(new LoggingHandler(),new MessageCodec());LoginRequestMessage message
= new LoginRequestMessage("zhangsan", "123");ByteBuf buf
= ByteBufAllocator.DEFAULT
.buffer();new MessageCodec().encode(null, message
, buf
);ByteBuf s1
= buf
.slice(0, 100);ByteBuf s2
= buf
.slice(100, buf
.readableBytes() - 100);s1
.retain(); channel
.writeInbound(s1
); }
}
- 加上 LengthFieldBasedFrameDecoder再測試
public class TestMessageCodec {public static void main(String[] args
) throws Exception {EmbeddedChannel channel
= new EmbeddedChannel(new LoggingHandler(),new LengthFieldBasedFrameDecoder(1024, 12, 4, 0, 0),
new LoggingHandler(),new MessageCodec());LoginRequestMessage message
= new LoginRequestMessage("zhangsan", "123");ByteBuf buf
= ByteBufAllocator.DEFAULT
.buffer();new MessageCodec().encode(null, message
, buf
);ByteBuf s1
= buf
.slice(0, 100);ByteBuf s2
= buf
.slice(100, buf
.readableBytes() - 100);s1
.retain(); channel
.writeInbound(s1
); }
}
可以看到,信息完整接收
參考視頻
總結
以上是生活随笔為你收集整理的Netty自定义协议的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。