正常情况下包的长度是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行
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行
这句话有问题,如果长度太大,肯定OOM
如果包大小超过最大内存限制,就必须每次读取一小段(比如1K),然后将数据写到文件系统,全部收取完毕后,在分段分析包至于粘包,很多人容易混淆了,tcp本身就不存在包的概念(记住:tcp是流协议),何来粘包之说?原则上tcp可以每次只发给你一个字节,因此不能依赖tcp每次接收的字节,而是自己要在应用协议部分做好识别(普遍做法是在应用数据包前端增加长度用于分包)
第一一个byte 长度1024之后用类似于byte[] buf=new byte[1024];
while((by=bis.read(buf))!=-1)
{
bos.write(buf,0,by);
}
,
粘包先看看编码吧 再就是分隔符是什么.. 代码有点懒得看.. 既然是自定义协议还是要讲讲协议吧