拆包
拆包是指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;
}
}
}