拆包
拆包是指netty傳輸資料時候,會把一條資訊,拆成幾部分。比如:"hello "拆成"he" 和 "llo"等,
粘包
粘包是指将多條資訊連在一起 比如發送“hello”和"123",而受到的是 "hello123"
解決方案:
- 消息定長,比如固定傳100字元,不夠的用空格補充
- 在尾部添加特殊字元
- 發送資訊是發送資訊長度
下面我們來看一下定長怎麼用
用戶端
@Data
public class MyMessageProtocol {
//定義一次發送包體長度
private int len;
//一次發送包體内容
private byte[] content;
}
public class NettyClientHandler extends SimpleChannelInboundHandler<MyMessageProtocol> {
/**
* 當用戶端連接配接伺服器完成就會觸發該方法
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
for(int i = 0; i< 10; i++) {
String msg = "檢測拆包";
//建立協定包對象
MyMessageProtocol messageProtocol = new MyMessageProtocol();
messageProtocol.setLen(msg.getBytes(CharsetUtil.UTF_8).length);
messageProtocol.setContent(msg.getBytes(CharsetUtil.UTF_8));
ctx.writeAndFlush(messageProtocol);
}
}
}
public class PackMessageEncoder extends MessageToByteEncoder<MyMessageProtocol> {
@Override
protected void encode(ChannelHandlerContext ctx, MyMessageProtocol msg, ByteBuf out) throws Exception {
System.out.println("MyMessageEncoder encode 方法被調用");
out.writeInt(msg.getLen());
out.writeInt(msg.getLen());
out.writeBytes(msg.getContent());
}
}
服務端
public class PackNettyServerHandler extends SimpleChannelInboundHandler<MyMessageProtocol> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyMessageProtocol msg) throws Exception {
System.out.println("====服務端接收到消息如下====");
System.out.println("長度=" + msg.getLen());
System.out.println("内容=" + new String(msg.getContent(), CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
public class PackMessageDecoder extends ByteToMessageDecoder {
int length = 0;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
//int類型長度4
if(in.readableBytes() >= 4) {
//擷取到長度
if (length == 0){
length = in.readInt();
}
if (in.readableBytes() < length) {
System.out.println("目前可讀資料不夠,繼續等待。。");
return;
}
byte[] content = new byte[length];
if (in.readableBytes() >= length){
in.readBytes(content);
//封裝成MyMessageProtocol對象,傳遞到下一個handler業務處理
MyMessageProtocol messageProtocol = new MyMessageProtocol();
messageProtocol.setLen(length);
messageProtocol.setContent(content);
//交給下個handler處理
out.add(messageProtocol);
}
length = 0;
}
}
}