6
回答
用Netty 作为server端实现,客户端实现没有采用netty,出现问题:数据包过大,服务端无法完整接收数据包!
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   

最近对Netty作了一些尝试,随意写了一个服务端,然后用tcp软件 发送 数据给 服务端,发现一个问题:

  当发送数据过大时,服务端就不能完整接收数据了,请问大侠们 如何解决这个问题的!

另:网上有很多关于 粘包 的处理方式,那是 针对 客户端/服务器端  都是采用netty实现的,或者已经事先约定好数据包格式的!

现在的问题 都不能达到 以上的 两个条件,我们又该如何去做呢!


自己实现的decode: 

@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
// TODO Auto-generated method stub
if (!msg.isReadable() || msg.readableBytes() <= 4)
            return;
String bufLen = msg.toString(0,4,charset);
long length = Long.valueOf(bufLen)+4;
        if (msg.readableBytes() < length)
            return;
        out.add(msg.readBytes((int)length).toString(charset));
}

但还是无法实现 接收 超过1K的 数据报文

举报
sunvim
发帖于4年前 6回/1K+阅
共有6个答案 最后回答: 4年前

解决方案之一(希望对后来人有所帮助):


package com.test.codec;


import java.nio.charset.Charset;
import java.util.List;


import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.handler.codec.MessageToMessageDecoder;


@Sharable
public class SandDecoder extends MessageToMessageDecoder<ByteBuf> {

private final Charset charset;
private int length=0;
private int recLen=0;
private String buffer="";
private boolean lenFlag=false;

public SandDecoder() {
// TODO Auto-generated constructor stub
this(Charset.defaultCharset());
}


public SandDecoder(Charset charset) {
// TODO Auto-generated constructor stub
if (charset == null) {
            throw new NullPointerException("charset");
        }
        this.charset = charset;
}


@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
// TODO Auto-generated method stub
if (!msg.isReadable() || msg.readableBytes() <= 4)
            return;
if(!lenFlag){
String bufLen = msg.toString(0,4,charset);
length = Integer.valueOf(bufLen)+4;
lenFlag = true;
}
recLen += msg.readableBytes() ;
buffer += msg.toString(charset);
        if (recLen < length ){
        System.out.println("test:"+length);
            return;
        }
        out.add(buffer);
        //init redo
        buffer="";
        recLen=0;
        lenFlag = false;
        length = 0;
            


}


}


--- 共有 1 条评论 ---
TinyZzh使用 LengthFieldBasedFrameDecoder 解码器。可以解决你的问题。不需要你写。希望对你有帮助。Netty本身提供了相当完善的解决粘包等问题 4年前 回复
用不用客户端跟netty没多大关系   netty已经提供了编解码的类,你自己处理下编解码就可以了。
--- 共有 1 条评论 ---
sunvim呵呵,不知道 怎么去做,能详细指明一下,谢谢了! 4年前 回复

netty4的话可以继承ByteToMessageDecoder,然后根据你的数据包大小进行接收。

@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
		if (!in.isReadable() || in.readableBytes() < 4)
			return;
		long length = in.getUnsignedInt(0) - 4;
		if (in.readableBytes() < length)
			return;
		out.add(in.readBytes((int)length));
		
	}



这样就行,neety3的大同小异

--- 共有 6 条评论 ---
sunvim呵呵,我能解出包的长度,但不知怎么去累积数据!思路是有的,不知道怎么去做! 4年前 回复
浪漫怕丑仔回复 @sunvim : 你自己写个解码类就行了,解出包的长度,读够长度再channelRead 4年前 回复
sunvim还是不会用,例如9086{……}这样格式的报文,我该怎么设置呢,9086是数据报文的长度,这个值是会改变的! 4年前 回复
浪漫怕丑仔回复 @sunvim : 估计是你处理有误吧,或者你直接用netty提供的解码类LengthFieldBasedFrameDecoder,下面是构造方法。 4年前 回复
sunvim我自己写了一个,decoder,但是还是无法解决 接收超过1K的数据报文,请再指导一下,谢谢! 4年前 回复
跟客户端用什么实现有啥关系,这是协议的问题,定好包头,一般包头里面有包长,可能还有其它数据,比如命令号等等,包长用4个字节表示,服务端取的时候也是按照协议解析的
--- 共有 2 条评论 ---
平安北京回复 @sunvim : 你下个CMPP协议吧 4年前 回复
sunvim多谢解答,能给一个简单的 代码内容么! 4年前 回复
自己定义一个decoder,然后加入到pipeline中去,将这个decoder继承DelimiterBasedFrameDecoder可以实现用特定符号分割的协议,ByteToMessageDecoder是所有的decoder的父类,netty帮我们做了很多常用协议的decoder, super.decode(ctx, buffer);之后再自己装换成自己想要的协议类。。。个人拙见,刚完成了一个客户端
--- 共有 1 条评论 ---
sunvim谢谢 提供解决思路,有空试试! 4年前 回复
顶部