正常情况下包的长度是9~500左右的长度的,后台基本不会发来大包,后台发送日志也是正常的,但是android 端就经常出现这个情况,要怎么处理,看了网上的文章,说是粘包,也提到一些思路,我这边是用自定义协议的,结合我的项目用代码实现思路也不清晰,希望大神路过指点一二。下面是错误信息
java.lang.OutOfMemoryError: Failed to allocate a 842019138 byte allocation with 16777216 free bytes and 481MB until OOM
    at fuhao.com.app.net.TcpSocketZ$ReceiveThread.run(TcpSocketZ.java:255)下面是代码:代码有点乱,还没做整理,这个是TcpSocket实现Runnable的run方法:
 @Override
        public synchronized void run() {
            try {
                int packetLen = 0;
                while (isRunning) {
                    if (!isConnected) {
                        mSocket = new Socket(HostIP, Port);
                        mSocket.setSendBufferSize(1024);
                        mSocket.setReceiveBufferSize(1024);
                        mSocket.setTcpNoDelay(true);
                        mSocket.setKeepAlive(true);
                        mDos = new DataOutputStream(mSocket.getOutputStream());
                        mDis = new DataInputStream(mSocket.getInputStream());
                        handshark();
                        isConnected = true;
                        startHeartBeat();
                    } else {
                        if (mDis.available() >= 4) {
                            packetLen = mDis.readInt();
                            L.e("TcpSocketZ", "-----packetLen------" + packetLen);
                            if (packetLen > 0) {
                                byte iszlib = mDis.readByte();
                                if (iszlib == (byte) 1) {
                                    try {
                                        byte[] inputData = new byte[packetLen - 1];
                                        utils.readData(mDis, inputData, 0, packetLen - 1);
                                        byte[] result = CompressUtil.decompress(inputData);
                                        byteReader br = new byteReader(result);
                                        int alias = br.readInt();
                                        L.e("TcpSocketZ", "recv packet zlib ------" + String.valueOf(alias));
                                        baseProto obj = ClassFactory.getProtoObject(alias);
                                        if (obj != null) {
                                            obj.parseFrom(br);
                                            EventBus.getDefault().post(new ResEvent(obj));
                                        }
                                    } catch (DataFormatException e) {
                                        e.printStackTrace();
                                    }
                                } else {
                                    byte[] inputData = new byte[packetLen - 1];
                                    utils.readData(mDis, inputData, 0, packetLen - 1);
                                    byteReader br = new byteReader(inputData);
                                    int alias = br.readInt();
                                    L.e("TcpSocketZ", "packet alias------" + String.valueOf(alias));
                                    if (alias == 20002) {
                                        backTime = 0;
                                    }
                                    baseProto obj = ClassFactory.getProtoObject(alias);
                                    if (obj != null) {
                                        obj.parseFrom(br);
                                        EventBus.getDefault().post(new ResEvent(obj));
                                    }
                                }
                            }
                        }
                    }
                }
                mDos.close();
                mDis.close();
                if (mSocket != null) {
                    mSocket.close();
                    mSocket = null;
                }
                this.isRunning = false;
                reconnect();
            } catch (EOFException e) {
                this.isConnected = false;
                try {
                    mDos.close();
                    mDis.close();
                    if (mSocket != null) {
                        mSocket.close();
                        mSocket = null;
                    }
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                reconnect();
                e.printStackTrace();
            } catch (SocketException e) {
                e.printStackTrace();
                this.isConnected = false;
                try {
                    mDos.close();
                    mDis.close();
                    if (mSocket != null) {
                        mSocket.close();
                        mSocket = null;
                    }
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                reconnect();
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
                this.isConnected = false;
                try {
                    mDos.close();
                    mDis.close();
                    if (mSocket != null) {
                        mSocket.close();
                        mSocket = null;
                    }
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                reconnect();
                e.printStackTrace();
            } catch (IOException e) {
                this.isConnected = false;
                try {
                    mDos.close();
                    mDis.close();
                    if (mSocket != null) {
                        mSocket.close();
                        mSocket = null;
                    }
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                reconnect();
                e.printStackTrace();
 
            }
        }错误的是出现在上面代码的第40行

解决方案 »

  1.   

    byte[] inputData = new byte[packetLen - 1];
    这句话有问题,如果长度太大,肯定OOM
    如果包大小超过最大内存限制,就必须每次读取一小段(比如1K),然后将数据写到文件系统,全部收取完毕后,在分段分析包至于粘包,很多人容易混淆了,tcp本身就不存在包的概念(记住:tcp是协议),何来粘包之说?原则上tcp可以每次只发给你一个字节,因此不能依赖tcp每次接收的字节,而是自己要在应用协议部分做好识别(普遍做法是在应用数据包前端增加长度用于分包)
      

  2.   


    第一一个byte 长度1024之后用类似于byte[] buf=new byte[1024];
    while((by=bis.read(buf))!=-1)
    {
    bos.write(buf,0,by);
    }
      

  3.   

    packetLen = mDis.readInt();,这是包剩余的字节数吧,这个肯定算错了。
      

  4.   

    我也遇到了一个问题,就是通过NIO接收,客户端循环发送太快会导致接收字节不对,如果间隔100Ms或者1s就没问题
      

  5.   

    OOM 啊  是一个socket多次发送请求的情况吗?
    粘包先看看编码吧  再就是分隔符是什么..  代码有点懒得看..   既然是自定义协议还是要讲讲协议吧