socket通信分包和粘包处理

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

//         
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值