用Netty 作为server端实现,客户端实现没有采用netty,出现问题:数据包过大,服务端无法完整接收数据包!

sunvim 发布于 2014/01/01 12:00
阅读 1K+
收藏 6

最近对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的 数据报文

加载中
0
sunvim
sunvim

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


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;
            


}


}


T
TinyZzh
使用 LengthFieldBasedFrameDecoder 解码器。可以解决你的问题。不需要你写。希望对你有帮助。Netty本身提供了相当完善的解决粘包等问题
0
星爷
星爷
用不用客户端跟netty没多大关系   netty已经提供了编解码的类,你自己处理下编解码就可以了。
sunvim
sunvim
呵呵,不知道 怎么去做,能详细指明一下,谢谢了!
0
浪漫怕丑仔
浪漫怕丑仔

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的大同小异

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