Netty5接收TCP数据分包问题

zhouyu7373 2014-10-22 09:46:42
使用netty5建立一个TCP的服务端进行接收数据,发送的数据是图片,大小约2mb左右。
在messageReceived接收数据的时候打印日志把消息存起来,发现出现断包的情况,第一包接收的数据是768个字符。
第一包和第二包都会被分成3个残包发送过来,第三包开始变成正常包。
求大神指点,能否将netty发送的数据每包设置大一些。
设置过下面这几个参数,但是没起作用。
bootstrap.childOption(ChannelOption.SO_RCVBUF, 2097152);
bootstrap.childOption(ChannelOption.MAX_MESSAGES_PER_READ, 2097152);

bootstrap = new ServerBootstrap();
//给group赋值
bootstrap.group(bossGroup, workerGroup);
//配置channel
bootstrap.channel(NioServerSocketChannel.class);
//加过滤条件
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//过滤编码
pipeline.addLast("decoder", new ByteArrayDecoder());
//过滤编码
pipeline.addLast("encoder", new ByteArrayEncoder());
//设置接收消息的处理类
pipeline.addLast("Process", receiveHandler);
}
});

因为我们的数据都是7E开头7E结尾的,而且消息体中也包含7E的消息,如果消息从任意一个位置断开了就不能对消息进行解析了。
...全文
855 11 打赏 收藏 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
悲剧的程序员 2014-11-06
  • 打赏
  • 举报
回复
解决了没有,典型的一个网络流断包,我是用mina做的,iobuffer这个网络流。你最好在传输的时候就知道整个包的长度是多少,例如2mb = 2048 k ,然后你设置这个包有多少字节。(定义一个包头)每次读的时候验证一下这个包是否带包头,不带那么肯定是断包了。如果是带包头的,将你的iobuffer重置一下位置。然后截取你的包长度,按照这个长度来解析,如果字节不够你的包长度,那么就等下一包。此问题就完美解决了。
lfengxu 2014-10-30
  • 打赏
  • 举报
回复
pipeline.addLast("framedecoder", new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4)) pipeline.addLast("frameencoder", new LengthFieldPrepender(1048576,4, 4)) 放在decoder的前面吧。
昆卡卡 2014-10-22
  • 打赏
  • 举报
回复
引用 4 楼 zhouyu7373 的回复:
[quote=引用 2 楼 yyy269954107 的回复:] 楼主我用的mina,也碰到过类似问题,网络的分包是不可避免的,特别是你传输的数据比较大时,我用的方法是自定义协议,有一个字段是数据区长度,一定要读取到指定的长度才认为这一条数据接收完成.看楼主是通过特定的数据头和数据尾进行的切分,这种情况就要保证传输的数据中没有你定义的头尾(7E),可以参考一下别人用的转义字符,数据区中遇到7E用转义字符表示,收到数据后再恢复成7E,这样楼主就可以根据7E进行数据包的切分了.不过我感觉还是通过长度来切分应该简单一点
这个是交通部的GPS通讯协议,我们用grizzly做通讯的时候不会出现这个问题,但是他的性能不够。换了netty5之后性能很好的但是netty5内部是异步的所以出现断包的问题,我对其他的协议做过转义和还原,但是这个协议的消息体中包含7E比较难判断,求大神指点一二啊!!![/quote] 比如我们规定转义字符是0x0a,在发送之前进行转义处理,你需要转义处理的就两个,0x7e和0x0a,比如你要发送数据0x7e 0x00 0x0a 0x7e转义后处理为0x0a (0x7e^0x0a) 0x00 0x0a (0x0a^0x0a) 0x0a (0x7e^0x0a) 收到数据后就需要注意0x0a了,把0x0a及其后一个字节进行转义回以前的字节,比如:0x0a (0x7e^0x0a)把这两个字节还原成(0x7e^0x0a)^0xoa,两次异或又会变成之前的数据,急着下班,可能讲的不够清楚,先看下吧
skgary 2014-10-22
  • 打赏
  • 举报
回复
你的协议是不是第二个字节或者2-3两个字节才是长度啊?
skgary 2014-10-22
  • 打赏
  • 举报
回复
如果是人家制定的,那应该就是理解上的问题了。
zhouyu7373 2014-10-22
  • 打赏
  • 举报
回复
引用 5 楼 skgary 的回复:
[quote=引用 3 楼 zhouyu7373 的回复:] [quote=引用 1 楼 skgary 的回复:] 这种情况 多数对端在768byte的时候直接flush了,你服务器端怎么改都没有用。 而且,不管你用什么API,都不能假设网络不分包。 所以,你应该想办法弄一个缓冲区,保证一次都读全一个包。
--------------------------------------------------------------------------------------------------- 这个消息是开头结尾都是7E,而且消息体中也有7E这样就很难缓存起来合成一个包。 而且如果消息断了,第一条中的一部分是没有消息头的很难判断啊,我也想过先把消息放到缓存里等所有的包都齐了再拆开,就是判断比较难[/quote] 那是你自己的通讯 协议设计的有问题。 建议必须 要有一个包头,然后有个包长度的字段。[/quote] 大神,这个协议是交通部定的,我们也改不了啊,除了改协议还有别的方法么?我刚又看了一遍协议,这里只有总包数和自己包的编号,没有消息长度
skgary 2014-10-22
  • 打赏
  • 举报
回复
引用 3 楼 zhouyu7373 的回复:
[quote=引用 1 楼 skgary 的回复:] 这种情况 多数对端在768byte的时候直接flush了,你服务器端怎么改都没有用。 而且,不管你用什么API,都不能假设网络不分包。 所以,你应该想办法弄一个缓冲区,保证一次都读全一个包。
--------------------------------------------------------------------------------------------------- 这个消息是开头结尾都是7E,而且消息体中也有7E这样就很难缓存起来合成一个包。 而且如果消息断了,第一条中的一部分是没有消息头的很难判断啊,我也想过先把消息放到缓存里等所有的包都齐了再拆开,就是判断比较难[/quote] 那是你自己的通讯 协议设计的有问题。 建议必须 要有一个包头,然后有个包长度的字段。
zhouyu7373 2014-10-22
  • 打赏
  • 举报
回复
引用 2 楼 yyy269954107 的回复:
楼主我用的mina,也碰到过类似问题,网络的分包是不可避免的,特别是你传输的数据比较大时,我用的方法是自定义协议,有一个字段是数据区长度,一定要读取到指定的长度才认为这一条数据接收完成.看楼主是通过特定的数据头和数据尾进行的切分,这种情况就要保证传输的数据中没有你定义的头尾(7E),可以参考一下别人用的转义字符,数据区中遇到7E用转义字符表示,收到数据后再恢复成7E,这样楼主就可以根据7E进行数据包的切分了.不过我感觉还是通过长度来切分应该简单一点
这个是交通部的GPS通讯协议,我们用grizzly做通讯的时候不会出现这个问题,但是他的性能不够。换了netty5之后性能很好的但是netty5内部是异步的所以出现断包的问题,我对其他的协议做过转义和还原,但是这个协议的消息体中包含7E比较难判断,求大神指点一二啊!!!
zhouyu7373 2014-10-22
  • 打赏
  • 举报
回复
引用 1 楼 skgary 的回复:
这种情况 多数对端在768byte的时候直接flush了,你服务器端怎么改都没有用。 而且,不管你用什么API,都不能假设网络不分包。 所以,你应该想办法弄一个缓冲区,保证一次都读全一个包。
--------------------------------------------------------------------------------------------------- 这个消息是开头结尾都是7E,而且消息体中也有7E这样就很难缓存起来合成一个包。 而且如果消息断了,第一条中的一部分是没有消息头的很难判断啊,我也想过先把消息放到缓存里等所有的包都齐了再拆开,就是判断比较难
昆卡卡 2014-10-22
  • 打赏
  • 举报
回复
楼主我用的mina,也碰到过类似问题,网络的分包是不可避免的,特别是你传输的数据比较大时,我用的方法是自定义协议,有一个字段是数据区长度,一定要读取到指定的长度才认为这一条数据接收完成.看楼主是通过特定的数据头和数据尾进行的切分,这种情况就要保证传输的数据中没有你定义的头尾(7E),可以参考一下别人用的转义字符,数据区中遇到7E用转义字符表示,收到数据后再恢复成7E,这样楼主就可以根据7E进行数据包的切分了.不过我感觉还是通过长度来切分应该简单一点
skgary 2014-10-22
  • 打赏
  • 举报
回复
这种情况 多数对端在768byte的时候直接flush了,你服务器端怎么改都没有用。 而且,不管你用什么API,都不能假设网络不分包。 所以,你应该想办法弄一个缓冲区,保证一次都读全一个包。

62,620

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧