socket自定義數據格式轉化二進制

自定義數據格式的方案

一般傳送的數據,肯定有消息類型,消息序列號,具體的自定義消息內容;
則可以先定義一個統一的格式:
prefix + packType(1) + seq(4) +[userData](標誌性前綴+消息類型+序列號+自定義數據)

封裝成byte[] 和解析數據過程

針對上面根據每種消息類型自定義的userData,可以這樣定義格式:
[filedType + filedLength+ filedValue](字段類型標誌+字段長度+字段值)

直接看例子
packData ()爲打包消息

public class Utils {
    byte PACKET_PREFIX = '$';
    int FILED_HEADER_LENGTH = 5;//因爲filedType爲byte + filedLength爲int,所以字段前綴長度爲5
    int MAX_PACKET_LENGTH = 1024;//包大小 1k
    int INT_LENGTH = 4;
    /**
     * 封裝報文
     * 協議:prefix + packType(1) + seq(4) +[userData]
     * prefix 標誌性前綴
     * packType - 報文類型
     * seq - 發送序列
     * userData - 用戶數據
     *
     * @param seq
     * @param packType
     * @param userData
     * @return
     */

    public static byte[] packData(int seq, byte packType, byte[] userData) {
        if (userData == null) {
            return null;
        }

        byte[] data = new byte[MAX_PACKET_LENGTH];
        int offset = 0;

        // 打包數據頭部
        //add prefix
        data[offset++] = PACKET_PREFIX;
        //add msgType
        data[offset++] = packType;

        //add seq
        addInt(data, offset, seq);

        offset += INT_LENGTH;
        if (data.length < offset + userData.length) {//數組大小不夠,則需要擴容
            byte[] tmp = new byte[offset + userData.length];
            System.arraycopy(data, 0, tmp, 0, offset);
            data = tmp;
        }

        System.arraycopy(userData, 0, data, offset, userData.length);
        offset += userData.length;

        byte[] result = new byte[offset];
        System.arraycopy(data, 0, result, 0, offset);

        return result;
    }

    public static int bytesToInt(byte[] src, int offset) {
        if (src == null || src.length < offset || offset + SearchConst.INT_LENGTH > src.length) {
            return -1;
        }
        int sendSeq;
        sendSeq = src[offset++] & 0xFF;
        sendSeq |= (src[offset++] << 8) & 0xFF00;
        sendSeq |= (src[offset++] << 16) & 0xFF0000;
        sendSeq |= (src[offset++] << 24) & 0xFF000000;
        return sendSeq;
    }

    public static byte[] intToBytes(int value) {
        byte[] src = new byte[4];
        src[0] = (byte) (value & 0xFF);
        src[1] = (byte) ((value >> 8) & 0xFF);
        src[2] = (byte) ((value >> 16) & 0xFF);
        src[3] = (byte) ((value >> 24) & 0xFF);
        return src;
    }

    public static void addInt(byte[] src, int offset, int value) {
        byte[] seqBytes = intToBytes(value);
        System.arraycopy(seqBytes, 0, src, offset, 4);
    }

     /**
     * [filedType + filedLength+ filedValue]
     *
     * @param src
     * @param filedBytes
     */
    public static void addFiledBytes(byte[] src, int offset, byte[] filedBytes, byte fieldType) {
        src[offset++] = fieldType;
        Utils.addInt(src, offset, filedBytes.length);
        offset += INT_LENGTH;
        System.arraycopy(filedBytes, 0, src, offset, filedBytes.length);
    }

下面爲自定義的數據DeviceData 如何和byte[] 相互轉化

public class DeviceData extends BaseUserData {
    private static final byte FIELD_TYPE_DEVID = 0x31;
    private static final byte FIELD_TYPE_SERVICENAME = 0x32;
    private static final byte FIELD_TYPE_PKGNAME = 0x33;
    private static final byte FIELD_TYPE_FUNCTION = 0x34;

    private String devId;//設備id
    private String serviceName;
    private String pkgName;
    private int func;//功能位

    public String getDevId() {
        return devId;
    }

    public void setDevId(String devId) {
        this.devId = devId;
    }

    public String getServiceName() {
        return serviceName;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }

    public String getPkgName() {
        return pkgName;
    }

    public void setPkgName(String pkgName) {
        this.pkgName = pkgName;
    }

    public int getFunc() {
        return func;
    }

    public void setFunc(int func) {
        this.func = func;
    }

    /**
     * [filedType + filedLength+ filedValue]
     *
     * @param device
     * @return
     */
    public static byte[] packDeviceData(DeviceData device) {
        if (device == null || device.getDevId() == null || device
                .getServiceName() == null || device.getPkgName() == null) {
            return null;
        }

        try {
            byte[] devIdBytes = device.getDevId().getBytes("UTF-8");
            byte[] serviceNameBytes = device.getServiceName().getBytes("UTF-8");
            byte[] pkgNameBytes = device.getPkgName().getBytes("UTF-8");
            byte[] funcBytes = Utils.intToBytes(device.getFunc());

            byte[] data = new byte[SearchConst.MAX_PACKET_LENGTH];
            int offset = 0;

            //add devId
            Utils.addFiledBytes(data, offset, devIdBytes, FIELD_TYPE_DEVID);
            offset += FILED_HEADER_LENGTH + devIdBytes.length;

            //add serviceName
            Utils.addFiledBytes(data, offset, serviceNameBytes, FIELD_TYPE_SERVICENAME);
            offset += FILED_HEADER_LENGTH + serviceNameBytes.length;

            //add pkgName
            Utils.addFiledBytes(data, offset, pkgNameBytes, FIELD_TYPE_PKGNAME);
            offset += FILED_HEADER_LENGTH + pkgNameBytes.length;

            //add func
            Utils.addFiledBytes(data, offset, funcBytes, FIELD_TYPE_FUNCTION);

            byte[] result = new byte[data.length];
            System.arraycopy(data, 0, result, 0, data.length);
            return result;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static DeviceData parseDeviceUserData(byte[] userData) {
        DeviceData device = new DeviceData();
        if (userData.length < FILED_HEADER_LENGTH) {
            return null;
        }
        int offset = 0;
        while (offset + FILED_HEADER_LENGTH < userData.length) {
            byte dataType = userData[offset++];
            int len = Utils.bytesToInt(userData, offset);
            offset += INT_LENGTH;

            if (len < 0 || len + offset > userData.length) {
                return null;
            }
            switch (dataType) {
                case FIELD_TYPE_DEVID:
                    String devId = null;
                    try {
                        devId = new String(userData, offset, len, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    device.setDevId(devId);
                    break;
                case FIELD_TYPE_SERVICENAME:
                    String serviceName = null;
                    try {
                        serviceName = new String(userData, offset, len, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    device.setServiceName(serviceName);
                    break;
                case FIELD_TYPE_PKGNAME:
                    String pkgName = null;
                    try {
                        pkgName = new String(userData, offset, len, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    device.setPkgName(pkgName);
                    break;
                case FIELD_TYPE_FUNCTION:
                    int func = Utils.bytesToInt(userData, offset);
                    if (func > 0) {
                        device.setFunc(func);
                    }
                    break;
                default:
            }
            offset += len;
        }
        return device;
    }

    @Override
    public String toString() {
        return "DeviceData={ip=" + ip + ",port=" + port + ",devId=" + devId + ",serviceName=" +
                serviceName + ",pkgName=" + pkgName + ",func=" + func + "}";
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章