【MML】華為MML AAA介面聯調,Java版本

来源:https://www.cnblogs.com/cutter-point/archive/2018/08/16/9490834.html
-Advertisement-
Play Games

1、我們先設置一些常量數據 2、創建對應的信息vo載體 3、創建編碼解碼器,進行報文的編碼解碼(關鍵,劃重點哦,特別是校驗和的計算) 4、創建對應的成幀器,來獲取發送每一幀信息 5、根據模板模式,設計模板類,用來與MML伺服器通信 6、發送指令操作 直接調用(各個地方的某些欄位可能不同,這個參考常量 ...


1、我們先設置一些常量數據

 

package cn.cutter.ztesoft.HuWeiMML.constrant;

/**
 * @description: AAA介面常量設置
 * @author: xiaof
 * @create: 2018-07-26 10:07
 **/
public class InfAAAMissionConstrant {

    /**
     *訂單號,工單號,寬頻賬號
     */
    public static final String AAA_ORDER_ID = "orderId";
    public static final String AAA_WORK_ORDER_ID = "workOrderId";
    public static final String AAA_ACCOUNT = "accNbr";
    public static final String USER_MOBILE = "mobile";

    /**
     * 配置信息
     */
//    public static final String IOM_IP;

    public static final String AAA_IP = "IP";
    public static final String AAA_PORT = "PORT";
    public static final String AAA_USER_NAME = "USERNAME";
    public static final String AAA_PASS_WORD = "PASSWORD";
    public static final String AAA_CONFIG_TYPE = "AAA_SOCKET_INFO";

    public static final String SERVICEFLAG = "AAA";

    //消息頭 AAA_MSG_STARTING_INT \x1C\x1D\x1E\x1F
    public static final String AAA_MSG_STARTING = "`SC`";

    public static final int AAA_MSG_STARTING_INT = 0x1C1D1E1F;

    public static final byte[] AAA_MSG_STARTING_BYTE = {0x1C, 0x1D, 0x1E, 0x1F};

    /**
     * AAA IIN類型格式發送位元組消息  0x60, 0x53, 0x43, 0x60
     */
    public static final byte[] AAA_IIN_MSG_STARTING_BYTE = {0x60, 0x53, 0x43, 0x60};

    public static final int AAA_MSG_STARTTAG_LEN = 4; //消息開始標識長度

    public static final int AAA_MSG_COMM_LEN = 12;

    /**
     * 消息頭長度
     */
    public static final int AAA_MSG_HEAD_LEN = 20;

    /**
     * 消息長度部位
     */
    public static final int AAA_MSG_INFO_LEN = 4;

    //消息版本號
    public static final String AAA_MSG_VERSION = "1.00";

    public static final Integer AAA_MSG_VERSION_LEN = 4;

    public static final int AAA_MSG_STARTING_LEN = 4;

    /**
     * 終端標識
     */
    public static final String AAA_MSG_TERMINAL = "internal";

    public static final Integer AAA_MSG_TERMINAL_LEN = 8;

    public static final Integer AAA_SERVICE_CODE_LEN = 8;

    public static final Integer AAA_MAX_HEAD_LEN = 56;

    //    會話控制字包括:DLGLGN,DLGBEG,DLGCON,DLGEND。
//    說明
//    操作員登錄MML Server時客戶端發DLGLGN,在進行其他操作時,客戶端均發DLGCON。
//    操作員退出時,MMLServer給營帳的返回消息中會話控制字為DLGEND,表示會話的結束。
    /**
     * 會話id長度
     */
    public static final int AAA_DLG_ID_LEN = 8;

    public static final String AAA_DLG_LGN = "DLGLGN";

    public static final String AAA_DLG_BEG = "DLGBEG";

    public static final String AAA_DLG_CON = "DLGCON";

    public static final String AAA_DLG_END = "DLGEND";

    /**
     * 會話控制字長度
     */
    public static final int AAA_DLG_CONTROLLER_LEN = 6;

    /**
     * 會話保留字
     */
    public static final int AAA_DLG_RSVD_LEN_DLGRSVD = 4;
    /**
     * 會話頭長度
     */
    public static final int AAA_DLG_HEAD_LEN = 18;


    //    事務控制字包括:TXBEG,TXCON,TXEND。
//    說明
//    由Provision發起的操作,其事務控制字填寫TXBEG。
//    當一條MML命令的消息結束時,MML Server返回給Provision的事務控制字為TXEND,表示一條事務結束。

    /**
     * 事務id長度
     */
    public static final int AAA_TX_ID_LEN = 8;

    public static final String AAA_TX_BEG = "TXBEG";

    public static final String AAA_TX_CON = "TXCON";

    public static final String AAA_TX_END = "TXEND";

    public static final Integer AAA_TX_CONTROLLER_LEN = 6;

    /**
     * 事務保留字長度
     */
    public static final int AAA_TX_RSVD_LEN_DLGRSVD = 4;

    /**
     * 事務頭長度
     */
    public static final int AAA_TX_HEAD_LEN = 18;

    /**
     * 校驗和長度
     */
    public static final Integer AAA_CHK_LEN = 4;

    /**
     * IIN校驗和長度
     */
    public static final Integer AAA_IIN_CHK_LEN = 8;

    /**
     * 報文欄位
     */
    /**
     * 返回值。十進位整數類型。
     * 0表示執行成功,其他返回值的解釋請參見DESC欄位
     */
    public static final String RETN = "RETN";

    /**
     * 查詢屬性名列表,以“&”分隔。
     */
    public static final String ATTR = "ATTR";

    /**
     * 返回的記錄的值,用&分割結果。s
     */
    public static final String RESULT = "RESULT";

}

 

 

2、創建對應的信息vo載體

package cn.cutter.ztesoft.HuWeiMML.vo;

/**
 * @program: 
 * @description:
 * @author: xiaof
 * @create: 2018-07-26 15:25
 **/
public class MsgInfo {
    /**
     * 消息和消息長度
     */
    private byte msg[];
    private int msgLen;

    //  查詢用戶信息獲取  用戶IP地址 USERIPADDRESS,USERPORT 用戶埠號,業務標識SERVICEFLAG 預設AAA
    private String userIpAddress;
    private String userPort;
    private String serviceFlag;

    //AAA服務類型,預設C280
    private String serviceCode = "C280";

    //AAA用來做指令標識
    private String workOrderId;

    private String userName;
    private String passWord;

    public byte[] getMsg() {
        return msg;
    }

    public void setMsg(byte[] msg) {
        this.msg = msg;
    }

    public int getMsgLen() {
        return msgLen;
    }

    public void setMsgLen(int msgLen) {
        this.msgLen = msgLen;
    }

    public String getUserIpAddress() {
        return userIpAddress;
    }

    public void setUserIpAddress(String userIpAddress) {
        this.userIpAddress = userIpAddress;
    }

    public String getUserPort() {
        return userPort;
    }

    public void setUserPort(String userPort) {
        this.userPort = userPort;
    }

    public String getServiceFlag() {
        return serviceFlag;
    }

    public void setServiceFlag(String serviceFlag) {
        this.serviceFlag = serviceFlag;
    }

    public String getServiceCode() {
        return serviceCode;
    }

    public void setServiceCode(String serviceCode) {
        this.serviceCode = serviceCode;
    }

    public String getWorkOrderId() {
        return workOrderId;
    }

    public void setWorkOrderId(String workOrderId) {
        this.workOrderId = workOrderId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }
}

 

3、創建編碼解碼器,進行報文的編碼解碼(關鍵,劃重點哦,特別是校驗和的計算)

package cn.cutter.ztesoft.HuWeiMML.Template;

import cn.cutter.ztesoft.HuWeiMML.vo.MsgInfo;

import java.io.IOException;

/**
 * @program: 
 * @description: MML消息解碼,編碼器
 * @author: xiaof
 * @create: 2018-08-15 11:38
 **/
public interface MsgCoder {

    /**
     * 指令編碼
     * @param msg
     * @return
     * @throws IOException
     */
    byte[] toWire(MsgInfo msg) throws IOException;

    /**
     * 指令解碼
     * @param input
     * @return
     * @throws IOException
     */
    byte[] fromWire(byte input[]) throws IOException;
}

 

package cn.cutter.ztesoft.HuWeiMML.Template;


import cn.cutter.ztesoft.HuWeiMML.constrant.InfAAAMissionConstrant;
import cn.cutter.ztesoft.HuWeiMML.vo.MsgInfo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.Arrays;

/**
 *
 *
 *                      1 1 1 1 1 1
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                       0x60, 0x53, 0x43, 0x60                    |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                      msg length 4B                              |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                                                                 |
 * |              msg head 20B                                       |
 * |                                                                 |
 * |                                                                 |
 * |                                                                 |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                                                                 |
 * |     Conversation head  (18B)                                    |
 * |                                                                 |
 * |                                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                                 |                               |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
 * |                                                                 |
 * |                transaction head (18)                            |
 * |                                                                 |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                                                                 |
 * ~             operator msg(N * 4B)                                ~
 * |                                                                 |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                                                                 |
 * |            check(8B)                                            |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 * @program: 
 * @description: MML指令編碼解析
 * @author: xiaof
 * @create: 2018-08-15 11:40
 **/
public class MMLMsgBinCoder implements MsgCoder {

    private static final Log logger = LogFactory.getLog(MMLMsgBinCoder.class);

    @Override
    public byte[] toWire(MsgInfo msg) {

        //1.輸出消息開始標識 4位元組
        byte beginMarkBytes[] = InfAAAMissionConstrant.AAA_IIN_MSG_STARTING_BYTE;

        //2.輸出消息的長度4位元組 從消息頭到操作信息結束(包括填充的空格)的長度,16進位字元(0-F)表示的16位整數(4B),取值範圍為56到65000(10進位)
        int msglen = InfAAAMissionConstrant.AAA_MAX_HEAD_LEN + msg.getMsgLen();
        int len = 4 - msglen % 4;
        msglen += len; //使消息長度為4位元組的倍數
        //轉換為16進位的字元
        byte msgLengthBytes[] = numToHexStr(msglen, InfAAAMissionConstrant.AAA_MSG_INFO_LEN).getBytes();

        //3.消息頭 20位元組 版本號(4B)+終端標識(8B)+服務名(8B)
        byte msgHeadBytes[] = msgHead(msg.getServiceCode());

        //4.會話頭 18位元組
        byte dlgrsvdBytes[] = dlgrsvd(msg.getUserIpAddress(), msg.getWorkOrderId());

        //5.事務頭 18位元組
        byte txheadBytes[] = txHead(msg.getUserIpAddress(), msg.getWorkOrderId());

        //6.操作信息N*4位元組
        int operatorLen = (4 - msg.getMsgLen() % 4) + msg.getMsgLen();
        String operatorMsg = changeToByteStr(new String(msg.getMsg()), operatorLen);
        byte operatorBytes[] = operatorMsg.getBytes();

        //7.校驗和 8位元組
//    校驗和=對“消息頭+會話頭+事務頭+操作信息”組成的字元數組按32位分段後異或所得的結果再取反得到的值。
        byte checkBytes[] = new byte[msglen];
        //消息頭 20B
        System.arraycopy(msgHeadBytes, 0, checkBytes, 0, InfAAAMissionConstrant.AAA_MSG_HEAD_LEN);
        //會話頭 18b
        System.arraycopy(dlgrsvdBytes, 0, checkBytes, 0 + InfAAAMissionConstrant.AAA_MSG_HEAD_LEN, InfAAAMissionConstrant.AAA_DLG_HEAD_LEN);
        //事務頭 18B
        System.arraycopy(txheadBytes, 0, checkBytes, InfAAAMissionConstrant.AAA_MSG_HEAD_LEN
                + InfAAAMissionConstrant.AAA_DLG_HEAD_LEN, InfAAAMissionConstrant.AAA_TX_HEAD_LEN);
        //操作信息
        System.arraycopy(operatorBytes, 0, checkBytes, InfAAAMissionConstrant.AAA_MSG_HEAD_LEN
                + InfAAAMissionConstrant.AAA_DLG_HEAD_LEN + InfAAAMissionConstrant.AAA_TX_HEAD_LEN, operatorLen);
//        byte checkModBytes[] = checkSum(msglen, checkBytes);
        byte checkModBytes[] = createCheckSumString(checkBytes);

        //組合所有信息=開始標識+消息長度+消息頭+會話頭+事務頭+操作信息+校驗和
        byte resultBytes[] = new byte[InfAAAMissionConstrant.AAA_MSG_STARTING_LEN + InfAAAMissionConstrant.AAA_MSG_INFO_LEN
                    + msglen + InfAAAMissionConstrant.AAA_IIN_CHK_LEN];
//        byte resultBytes[] = new byte[InfAAAMissionConstrant.AAA_MSG_STARTING_LEN + InfAAAMissionConstrant.AAA_MSG_INFO_LEN
//                    + msglen];


        //開始標識 4B
        System.arraycopy(InfAAAMissionConstrant.AAA_IIN_MSG_STARTING_BYTE, 0, resultBytes, 0,
                InfAAAMissionConstrant.AAA_IIN_MSG_STARTING_BYTE.length);
        //消息長度 4B
        System.arraycopy(msgLengthBytes, 0, resultBytes, InfAAAMissionConstrant.AAA_IIN_MSG_STARTING_BYTE.length,
                msgLengthBytes.length);
        //消息頭 20B  消息頭+會話頭+事務頭+操作信息
        System.arraycopy(checkBytes, 0, resultBytes, InfAAAMissionConstrant.AAA_IIN_MSG_STARTING_BYTE.length
                        + msgLengthBytes.length, checkBytes.length);
//        校驗和
        System.arraycopy(checkModBytes, 0, resultBytes, InfAAAMissionConstrant.AAA_IIN_MSG_STARTING_BYTE.length
                        + msgLengthBytes.length + checkBytes.length, checkModBytes.length);

        return resultBytes;
    }

    @Override
    public byte[] fromWire(byte[] input) {
        //1.讀取MML不包含開始標識和長度位元組
        byte curBytes[] = input;
        byte msgBytes[] = null;

        try {
            //2.解析消息頭(20B)=版本號(4B)+終端標識(8B)+服務名(8B)
            curBytes = Arrays.copyOfRange(curBytes, InfAAAMissionConstrant.AAA_MSG_VERSION_LEN
                    + InfAAAMissionConstrant.AAA_MSG_TERMINAL_LEN + InfAAAMissionConstrant.AAA_SERVICE_CODE_LEN, curBytes.length);

            //3.解碼會話頭 會話頭(18)=會話ID(8B)+會話控制字(6B)+會話保留字(4B)
            curBytes = Arrays.copyOfRange(curBytes, InfAAAMissionConstrant.AAA_DLG_ID_LEN
                    + InfAAAMissionConstrant.AAA_DLG_CONTROLLER_LEN + InfAAAMissionConstrant.AAA_DLG_RSVD_LEN_DLGRSVD, curBytes.length);

            //4.解碼事務頭 事務頭=事務ID(8B)+事務控制字(6B)+事務保留字(4B)
            curBytes = Arrays.copyOfRange(curBytes, InfAAAMissionConstrant.AAA_TX_ID_LEN
                    + InfAAAMissionConstrant.AAA_TX_CONTROLLER_LEN + InfAAAMissionConstrant.AAA_DLG_RSVD_LEN_DLGRSVD, curBytes.length);

            //5.解碼操作信息
            int recMsgLen = input.length - InfAAAMissionConstrant.AAA_MAX_HEAD_LEN - InfAAAMissionConstrant.AAA_IIN_CHK_LEN;
            msgBytes = Arrays.copyOfRange(curBytes, 0, recMsgLen);

            //6.解碼校驗和 “消息頭+會話頭+事務頭+操作信息”組成的字元數組按32位分段後異或所得的結果再取反得到的值。
            curBytes = Arrays.copyOfRange(curBytes, recMsgLen, InfAAAMissionConstrant.AAA_IIN_CHK_LEN);
            byte chkBytes[] = Arrays.copyOfRange(input, 0, InfAAAMissionConstrant.AAA_MAX_HEAD_LEN);

            //計算校驗和
            byte chkStr[] = createCheckSumString(chkBytes);
            //7.判斷校驗是否通過
            if(Arrays.equals(curBytes, chkBytes)) {
                throw new Exception("校驗不匹配");
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        //8.返回解碼之後的信息
        return msgBytes;
    }

    public static byte[] createCkeckSum(byte msg[])
    {
        int i = 0;
        int j = 0;
        byte checksum[] = new byte[4];
        for (i = 0; i < msg.length / 4; i++)
            for (j = 0; j < 4; j++)
                checksum[j] ^= msg[i * 4 + j];


        for (j = 0; j < msg.length % 4; j++)
            checksum[j] ^= msg[i * 4 + j];

        for (i = 0; i < 4; i++)
        {
            int k = ~checksum[i] & 0xff;
            checksum[i] = (byte)k;
        }

        return checksum;
    }

    public static byte[] createCheckSumString(byte msg[])
    {
        byte checksum[] = createCkeckSum(msg);
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 4; i++)
        {
            String s = Integer.toHexString(checksum[i] & 0xff).toUpperCase();
            if (s.length() < 2)
                sb.append("0").append(s);
            else
                sb.append(s);
        }

        return sb.toString().getBytes();
    }




    private String numToHexStr(int numCount, int defaultLen) {

//        StringBuffer sb = new StringBuffer();
        //1.10進位轉換為16進位,並且是4位的16進位
        StringBuffer hexStr = new StringBuffer(Integer.toHexString(numCount));
        for(int i = hexStr.length(); i < defaultLen; ++i) {
            hexStr.insert(0, '0');
        }

        return hexStr.toString();
    }

    private String changeToByteStr(String str, int defaultLen) {
        StringBuffer sourceSb = new StringBuffer();

        //判斷目標字元串是否滿足對應長度要求
        int i = 0;
        while(i < defaultLen) {

            if(i < str.length()) {
                sourceSb.append(str.charAt(i));
            } else {
                sourceSb.append(" ");
            }

            ++i;
        }
        return sourceSb.toString();
    }

    /**
     * 消息頭=版本號(4B)+終端標識(8B)+服務名(8B)
     * 消息頭20個位元組
     */
    private byte[] msgHead(String serviceCode) {
        StringBuffer sb = new StringBuffer();
        //版本號 4個位元組

        sb.append(changeToByteStr(InfAAAMissionConstrant.AAA_MSG_VERSION, InfAAAMissionConstrant.AAA_MSG_VERSION_LEN));

        //終端標識
        sb.append(changeToByteStr(InfAAAMissionConstrant.AAA_MSG_TERMINAL, InfAAAMissionConstrant.AAA_MSG_TERMINAL_LEN));

        //服務名,不出什麼意外,預設就是C280
        sb.append(changeToByteStr(serviceCode, InfAAAMissionConstrant.AAA_SERVICE_CODE_LEN));

        return sb.toString().getBytes();
    }

    /**
     * 會話頭信息
     * 會話頭=會話ID(8B)+會話控制字(6B)+會話保留字(4B)
     */
    private byte[] dlgrsvd(String ip, String workOrderId) {
        StringBuffer sb = new StringBuffer();
        //我們會話id 工單id
//        String plgid = changeToByteStr(workOrderId, InfAAAMissionConstrant.AAA_DLG_ID_LEN);
        String plgid = numToHexStr(Integer.valueOf(workOrderId), InfAAAMissionConstrant.AAA_DLG_ID_LEN);
        sb.append(plgid);
//        會話控制字包括:DLGLGN,DLGBEG,DLGCON,DLGEND。
//        說明
//        操作員登錄MML Server時客戶端發DLGLGN,在進行其他操作時,客戶端均發DLGCON。
//        操作員退出時,MMLServer給營帳的返回消息中會話控制字為DLGEND,表示會話的結束。
        sb.append(changeToByteStr(InfAAAMissionConstrant.AAA_DLG_LGN, InfAAAMissionConstrant.AAA_DLG_CONTROLLER_LEN));
        //會話保留字
//        會話保留字與事務保留字共同存儲IP地址。
//        說明  長度為4個位元組的十六進位字元
//        訪問AAA客戶端的IP地址,並使用會話保留字和事務保留字傳遞客戶端的IP地址。
//        例如:十進位的IP地址為長度為4個位元組的十六進位字元10.10.25.1,轉換為十六進位的IP地址為A.A.19.1,前4個位元組存儲到會話保留字中,後4個位元組保留到事務保留字。
//        String ip = "127.0.0.1";
        String ipNum[] = ip.split("\\.");
        StringBuffer ipSb = new StringBuffer();

        //獲取十進位的IP地址為長度為4個位元組的十六進位字元10.10.25.1,轉換為十六進位的IP地址為A.A.19.1,前4個位元組存儲到會話保留字中,後4個位元組保留到事務保留字。
        //1.迴圈遍歷4個數據,轉換為16進位字元串,取前4個位元組
        for(int i = 0; i < ipNum.length; ++i) {
            String hexStr = " ";
            if(!ipNum[i].equals("")) {
                hexStr = Integer.toHexString(Integer.valueOf(ipNum[i]));
            }
            for(int j = hexStr.length(); j < 2; ++j) {
                hexStr = "0" + hexStr;
            }
            ipSb.append(hexStr);
        }
        //刪除最後一個點
//        ipSb.deleteCharAt(ipSb.length() - 1);

        sb.append(changeToByteStr(ipSb.substring(0, 4), InfAAAMissionConstrant.AAA_DLG_RSVD_LEN_DLGRSVD));

        return sb.toString().getBytes();
    }

    /**
     * 事務頭=事務ID(8B)+事務控制字(6B)+事務保留字(4B)
     * @return
     */
    private byte[] txHead(String ip, String workOrderId) {
//        事務ID由客戶端產生。如果沒有並行的操作,所有的事務ID都可以填1。如果需要使用並行操作,則客戶端必須保證當前並行的所有操作中事務ID是不同的。
//        長度為8個位元組的整數,用16進位字元表示。
        StringBuffer sb = new StringBuffer();

        //事務id
        String txId = numToHexStr(Integer.valueOf(workOrderId), InfAAAMissionConstrant.AAA_TX_ID_LEN);
        sb.append(txId);
//        事務控制字包括:TXBEG,TXCON,TXEND。
//        說明
//        由Provision發起的操作,其事務控制字填寫TXBEG。
//        當一條MML命令的消息結束時,MML Server返回給Provision的事務控制字為TXEND,表示一條事務結束。
        String txControl = InfAAAMissionConstrant.AAA_TX_CON;
        sb.append(changeToByteStr(txControl, InfAAAMissionConstrant.AAA_TX_CONTROLLER_LEN));
        //事務保留字(4B)
//        訪問AAA客戶端的IP地址,並使用會話保留字和事務保留字傳遞客戶端的IP地址。
//        AAA訪問客戶端的IP地址,並使用會話保留字和事務保留字傳遞客戶端的IP地址。 例如:十進位的IP地址為長度為4個位元組的十六進位字元10.10.25.1,
// 轉換為十六進位的IP地址為A.A.19.1,前4個位元組存儲到會話保留字中,後4個位元組保留到事務保留字。 長度為4個位元組的十六進位字元
        //1.分解ip,取後置的4個位元組
        String ipNum[] = ip.split("\\.");
        //組裝16進位值
        StringBuffer hexStr = new StringBuffer();
        for(int i = 0; i < ipNum.length; ++i) {
            hexStr.append(Integer.toHexString(Integer.valueOf(ipNum[i]))).append(".");
        }

        hexStr = hexStr.deleteCharAt(hexStr.length() - 1);
        //取最後4個位元組
//        String ipResult = hexStr.substring(hexStr.length() - 4, hexStr.length());
        //事務頭=事務ID(8B)+事務控制字(6B)+事務保留字(4B)
        sb.append(changeToByteStr(hexStr.substring(hexStr.length() - 4, hexStr.length()), InfAAAMissionConstrant.AAA_TX_RSVD_LEN_DLGRSVD));

        return sb.toString().getBytes();
    }

    /**
     * 校驗和IIN模式 4位元組
     * 校驗和=對“消息頭+會話頭+事務頭+操作信息”組成的字元數組按32位分段後異或所得的結果再取反得到的值
     * @return
     */
    private byte[] checkSum(int msgLen, byte msg[]) {
        byte res[] = new byte[4];

        for(int i = 0; i < msgLen; i+=4) {
            res[0] ^= msg[i + 0];
            res[1] ^= msg[i + 1];
            res[2] ^= msg[i + 2];
            res[3] ^= msg[i + 3];
        }

        //最後取反
        res[0] = (byte) ~res[0];
        res[1] = (byte) ~res[1];
        res[2] = (byte) ~res[2];
        res[3] = (byte) ~res[3];

        String resStr = new String("");
        for (int i = 0; i < 4; i++) {
            resStr = resStr + byte2hex(res[i]);
        }

//        String resStr = new String(res);
//        for (int i = 0; i < 4; i++) {
//            resStr = resStr + byte2hex(res[i]);
//        }

        // 將16進位數擴展為對應字元數組(如0xE8--->"E8")
//        for(int i = 7; i >= 0; --i) {
//            if(i % 2 == 1) {
//                //低4位所代表16進位表字元擴展為一個位元組
//                res[i] = (byte) (res[i / 2] & 0x0F + '0');
//                if(res[i] > '9') {
//                    res[i] = (byte) (res[i] + 'A' - '0' - 10);
//                }
//            } else {
//                ////高4位所代表16進位表字元擴展為一個位元組
//                res[i] = (byte) (((res[i / 2] >> 4) & 0x0F) + '0');
//                if(res[i] > '9') {
//                    res[i] = (byte) (res[i] + 'A' - '0' - 10);
//                }
//            }
//        }


        return resStr.getBytes();
    }

    /**
     * 將單位元組轉成16進位
     *
     * @param b
     * @return
     */
    private String byte2hex(byte b) {
        StringBuffer buf = new StringBuffer();
        char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        int high = ((b & 0xf0) >> 4);
        int low = (b & 0x0f);
        buf.append(hexChars[high]);
        buf.append(hexChars[low]);
        return buf.toString();
    }

}

 

 

 

4、創建對應的成幀器,來獲取發送每一幀信息

 

package cn.cutter.ztesoft.HuWeiMML.Template;

import java.io.IOException;
import java.io.OutputStream;

/**
 * @program: 
 * @description: 成幀器
 * @author: xiaof
 * @create: 2018-08-15 10:34
 **/
public interface Framer {

    /**
     * 添加成幀信息並將制定消息輸出到制定流
     * @param message
     * @param out
     * @throws IOException
     */
    void frameMsg(byte message[], OutputStream out) throws IOException;

    /**
     * 掃描指定的流,抽取下一條消息
     * @return
     * @throws IOException
     */
    byte[] nextMsg() throws IOException;

}

 

package cn.cutter.ztesoft.HuWeiMML.Template;

import cn.cutter.ztesoft.HuWeiMML.constrant.InfAAAMissionConstrant;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;

/**
 * @program: 
 * @description: MML成幀器
 * @author: xiaof
 * @create: 2018-08-15 10:35
 **/
public class MMLFramer implements Framer {

    private static final Log logger = LogFactory.getLog(MMLFramer.class);

    private static final int MAX_MESSAGE_LENGTH = 65535;
    private static final int BYTE_MASK = 0xff;
    private static final int SHORT_MASK = 0xffff;
    private static final int BYTE_SHIFT = 8;

    private DataInputStream in;

    public MMLFramer(InputStream in) {
        this.in = new DataInputStream(in);
    }

    @Override
    public void frameMsg(byte[] message, OutputStream out) throws IOException {
        //1.判斷消息是否超長了
        if(message.length > MAX_MESSAGE_LENGTH) {
            throw new IOException("消息超長了");
        }

        //輸出消息
        out.write(message);
        out.flush();
    }

    @Override
    public by

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 給定一個大小為 n 的數組,找到其中的眾數。眾數是指在數組中出現次數大於 ⌊ n/2 ⌋ 的元素。 你可以假設數組是非空的,並且給定的數組總是存在眾數。 示例 1: 輸入: [3,2,3] 輸出: 3 示例 2: 輸入: [2,2,1,1,1,2,2] 輸出: 2 class Solution(ob ...
  • 給定一個正整數,返回它在 Excel 表中相對應的列名稱。 例如, 1 -> A 2 -> B 3 -> C ... 26 -> Z 27 -> AA 28 -> AB ... 示例 1: 輸入: 1 輸出: "A" 示例 2: 輸入: 28 輸出: "AB" 示例 3: 輸入: 701 輸出: " ...
  • $array[$j]){ $temp = $array[$i]; $array[$i] = $array[$j]; $array[$j] = $temp; } } } return $ar... ...
  • 給定一個已按照升序排列 的有序數組,找到兩個數使得它們相加之和等於目標數。 函數應該返回這兩個下標值index1 和 index2,其中 index1 必須小於 index2。 說明: 返回的下標值(index1 和 index2)不是從零開始的。 你可以假設每個輸入只對應唯一的答案,而且你不可以重 ...
  • 很多項目中都會遇到需要定時任務的情況,本篇文章就結合了Spring中以及SpringBoot、SpringCloud中定時任務的解決方案。 在Spring中使用定時器 用SpringBoot比較多的同學可能都會覺得Spring的xml配置確實比較麻煩,如果想在Spring中使用定時器的話其實是必須使 ...
  • 幾個複雜的ORM方式都已介紹完了,剩下一些常用的刪除、獲取記錄數量、統計合計數、獲取最大值、獲取最小值等方法我就不一一詳細介紹了,直接給出代碼大家自行查看。 1 #!/usr/bin/env python 2 # coding=utf-8 3 4 from common import db_help ...
  • 編寫一個程式,找到兩個單鏈表相交的起始節點。 例如,下麵的兩個鏈表: 在節點 c1 開始相交。 註意: 如果兩個鏈表沒有交點,返回 null. 在返回結果後,兩個鏈表仍須保持原有的結構。 可假定整個鏈表結構中沒有迴圈。 程式儘量滿足 O(n) 時間複雜度,且僅用 O(1) 記憶體。 ...
  • 題目 Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...