socket通信当中经常会遇到消息长度超过一包数据最大长度,需要分包、粘包处理,只需要按照消息包结构进行封装解析即可。下面记录一下我工作中的socket分包和粘包处理方法,需要的朋友可以参考这个思路,下面贴出代码:
package carnetapp.mms.command.serialport;
import android.util.Log;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import carnetapp.mms.aidl.Constants;
import carnetapp.mms.interfaces.UartListener;
import carnetapp.mms.util.ByteTool;
/**
* 串口数据接收粘包管理类
*/
public class UartReceiveHandler {
/**
* 存放接收数据的队列
*/
private Queue<byte[]> receiveQueue = new LinkedList<>();
/**
* 接收锁
*/
private Object receiveLock = new Object();
private ReceiveThread receiveThread;
private int length;
private int totalPackae;
private int packageNum;
private byte type;
private byte port;
//存放最终拼包数据的集合
private List<Byte> receiveList = new ArrayList<>();
//存放所有type和port相同需要拼包的包数据
private List<byte[]> spellPackages = new ArrayList<>();
private UartListener uartListener;
private boolean isReceiveRun = false;
/**
* 当前粘包处理状态
*/
private int receiveState = ReceiveState.START;
public UartReceiveHandler() {
init();
}
private void init() {
receiveThread = new ReceiveThread();
receiveThread.setName("UartReceiveHandler.ReceiveThread");
if (null != receiveThread && receiveThread.getState() != Thread.State.RUNNABLE && !receiveThread.isAlive()) {
isReceiveRun = true;
receiveThread.setPriority(Thread.MAX_PRIORITY);
receiveThread.start();
}
}
public void receiveData(byte[] data) {
if (null != data && data.length > 0) {
synchronized (receiveLock) {
receiveQueue.offer(data);
receiveThread.receiveNotify();
}
}
}
public void setUartListener(UartListener uartListener) {
this.uartListener = uartListener;
}
/**
* 接收数据线程
*/
private class ReceiveThread extends Thread {
private boolean isFinish = true;
/**
* 临时存放type和port不一样的报数据的队列
*/
private Queue<byte[]> cacheQueue = new LinkedList<>();
@Override
public void run() {
while (isReceiveRun) {
if (isInterrupted()) {
return;
}
if (!receiveQueue.isEmpty() && isFinish) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
receiveMsg();
}
} else {
receiveWait();
}
}
}
public void receiveWait() {
synchronized (ReceiveThread.this) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void receiveNotify() {
if (getState() == State.WAITING) {
synchronized (ReceiveThread.this) {
notify();
}
}
}
private synchronized void receiveMsg() {
isFinish = false;
byte[] buff = null;
if (!receiveQueue.isEmpty()) {
buff = receiveQueue.peek();
Log.i("DDD", "从接收队列中取出一包数据" + ByteTool.logBytes(buff));
synchronized (receiveLock) {
switch (receiveState) {
case ReceiveState.START:
//从接收队列取出一包数据,先不移除
//取出串口数据:09 03 0a 01 01 02 03 01 0d
//