JAVA 实现SECS/GEM通信协议之报文解析

废话不说,直接上代码

一、协议解析

        //获取字节流
	byte[] data = is.read(buf);
        // 判断数据长度是否异常
        if (length < 10) {
            throw new SecsParseException(String.format("Incomplete message (message length: %d)", length));
        }
        //取前四个字节,得到数据长度
        byte[] lengthField = new byte[4];
        System.arraycopy(data, 0, lengthField, 0, 4);
        long messageLength = new U4(lengthField).getValue(0);
        //解析消息头
        
        //解析sessionId
        byte[] sessionIdBuf = new byte[2];
        System.arraycopy(data, 4 , sessionIdBuf, 0, 2);
        int sessionId = (int) ConversionUtils.bytesToUnsignedInteger(sessionIdBuf);
        
        //获取头部字节
        byte headerByte2 = data[4 + 2];
        byte headerByte3 = data[4 + 3];
        
        //解析标识类型
        byte pTypeByte = data[4 + 4];
        PType pType = PType.parse(pTypeByte);
        if (pType != PType.SECS_II) {
            throw new SecsParseException(String.format("Unsupported protocol; not SECS-II (PType: %d)", pTypeByte));
        }
        
        //解析会话类型
        byte sTypeByte = data[4 + 5];
        SType sType = SType.parse(sTypeByte);
        if (sType == SType.UNKNOWN) {
            throw new SecsParseException(String.format("Unsupported message type (SType: %02x)", sTypeByte));
        }
        
        //解析系统字节
        byte[] transactionIdBuf = new byte[4];
        System.arraycopy(data, 4 + 6, transactionIdBuf, 0, 4);
        long transactionId = ConversionUtils.bytesToUnsignedInteger(transactionIdBuf);
        
        if (sType == 0x00) {
            //消息文本长度 = 报文消息长度 - 消息头长度
            int dataLength = (int) (messageLength - SecsConstants.HEADER_LENGTH);
            Data<?> text = null;
            if (dataLength > 0) {
                byte[] textBytes = new byte[dataLength];
                System.arraycopy(data, 14, textBytes, 0, dataLength);
                text = parseData(textBytes, 0);
            }
            int stream = headerByte2 & STREAM_MASK;//最高位表示是否回复,所以这里只取低7位的值 例:10000001 & 01111111 = 00000001
            int function = headerByte3;
	    boolean isReply = withReply(headerByte2);
	    SecsMessage dataMessage = new SecsMessage(stream,function,isReply);
	    dataMessage.setSessionId(sessionId);
            dataMessage.setTransactionId(transactionId);
            dataMessage.setData(text);
            //解析结束
        } else {
            ControlMessage controlMessage = new ControlMessage(sessionId, headerByte2, headerByte3, sType, transactionId);
	    //解析结束
        }

二、数据内容解析

	/**
     * 解析数据
     * @param data   字节流数据
     * @param offset 起始解析位置
     * @return
     */
	private static Data<?> parseData(byte[] data, int offset){
        if (data.length < 2) {
            throw new SecsParseException("Invalid data length: " + data.length);
        }
        //获取格式字节
        int formatByte = data[offset];
	//获取数据项格式代码
        int formatCode = (formatByte & 0xfc)>>2;
	//获取长度字节数
        int noOfLengthBytes = formatByte & 0x03;
        if (noOfLengthBytes < 1 || noOfLengthBytes > LENGTH_LENGTH) {
            throw new SecsParseException("Invalid number of length bytes: " + noOfLengthBytes);
        }
        if (data.length < noOfLengthBytes + 1) {
            throw new SecsParseException("Incomplete message data");
        }
	//解析长度字节,获取数据总长度(单位:字节)
        int length = data[offset + 1];
        if (noOfLengthBytes > 1) {
            length |= (data[offset + 2] << 8);
        }
        if (noOfLengthBytes > 2) {
            length |= (data[offset + 3] << 16);
        }
        if (data.length < offset + 2 + length) {
            throw new SecsParseException("Incomplete message data");
        }
        
        Data<?> dataItem = null;
        offset += (1 + noOfLengthBytes);
        switch (formatCode) {
            case L.FORMAT_CODE:
                dataItem = parseL(data, offset, length);
                break;
            case BOOLEAN.FORMAT_CODE:
                dataItem = parseBoolean(data, offset, length);
                break;
            case B.FORMAT_CODE:
                dataItem = parseB(data, offset, length);
                break;
            case A.FORMAT_CODE:
                dataItem = parseA(data, offset, length);
                break;
            case I1.FORMAT_CODE:
                dataItem = parseI1(data, offset, length);
                break;
            case I2.FORMAT_CODE:
                dataItem = parseI2(data, offset, length);
                break;
            case I4.FORMAT_CODE:
                dataItem = parseI4(data, offset, length);
                break;
            case I8.FORMAT_CODE:
                dataItem = parseI8(data, offset, length);
                break;
            case U1.FORMAT_CODE:
                dataItem = parseU1(data, offset, length);
                break;
            case U2.FORMAT_CODE:
                dataItem = parseU2(data, offset, length);
                break;
            case U4.FORMAT_CODE:
                dataItem = parseU4(data, offset, length);
                break;
            case U8.FORMAT_CODE:
                dataItem = parseU8(data, offset, length);
                break;
            case F4.FORMAT_CODE:
                dataItem = parseF4(data, offset, length);
                break;
            case F8.FORMAT_CODE:
                dataItem = parseF8(data, offset, length);
                break;
            default:
                throw new IllegalArgumentException(String.format("Invalid format code in message data: %02x", formatCode));
        }
        return dataItem;
    }

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值