JAVA Mina中使用Xmodem1k協議發送文件進行遠程升級

一、xdmodem1k的具體協議介紹這裏不再做詳細的解釋只簡單描述

    xmodem1k協議發送數據的數據包格式:

   <STX><包序號><包序號反碼><文件數據(1024字節)><校驗位>

0x02

STX: 包頭

0x04

EOT: 結束文件傳輸

0x06

ACK: 正常響應,如:數據包正確接收

0x15

NACK: 非正常響應

0x18

CAN: 取消文件傳輸

0x43

C: ASCII字符C

二、xmodem1k發送的流程(Mina socket作爲發送方)

1:建立Socket連接

2:接收方發送C到服務端   0x43

3:服務端接收到43開始解析文件發送第一幀包的數據到接收方

4:接收方收到正確數據返回0x06即ACK

6:如果發送方收到0x15則需要重發上一次發的包

7:如果發送方收到0x18則需要無條件終止發送,出現了嚴重錯誤。


三、JAVA代碼示例:

   // 開始
    private final byte SOH = 0x01;
    // 結束
    private final byte EOT = 0x04;
    // 應答
    private final byte ACK = 0x06;
    // 重傳
    private final byte NAK = 0x15;
    // 無條件結束

    private final byte CAN = 0x18;

   // 開始

    private  final byte STX=0x02;

    // 以128字節塊的形式傳輸數據
    private final int SECTOR_SIZE = 1024;
    // 最大錯誤(無應答)包數

    private final int MAX_ERRORS = 10;

   //path要發送的文件的路徑,deviceNo是設備唯一編號

   public void saveXmodemData(Path path,String deviceNo){
       // 包序號
        byte blockNumber = 0x01;
        // 校驗和
        int checkSum;
        // 讀取到緩衝區的字節數量
        int nbytes;
        // 初始化數據緩衝區
        byte[] sector = new byte[SECTOR_SIZE];
        int num=1;
        try {
    DataInputStream inputStream = new DataInputStream(Files.newInputStream(path));
    IoBuffer iobuffer=null;
     
    while ((nbytes = inputStream.read(sector)) > 0) {
        int inputLenth=inputStream.available();
          // 如果數據包小於1024個字節,以0x1A補齊 
          if (nbytes < SECTOR_SIZE) {
                 for (int i = nbytes; i < SECTOR_SIZE; i++) {
                sector[i] = (byte) 0x1A;
                 }
             }
          StringBuffer result=new StringBuffer();
          result.append(HexUtil.BytetoHexString(STX));
          result.append(HexUtil.BytetoHexString(blockNumber));
          result.append(HexUtil.BytetoHexString(((byte)~blockNumber)));
          result.append(HexUtil.Bytes2HexString(sector));
          String checkNum=byteToCrcNum(HexUtil.Bytes2HexString(sector));
          result.append(checkNum);
           byte[] resultData=HexUtil.HexString2Bytes(result.toString());

         //可以根據設備編號和序列將resultData保存起來,後面在Handler類中根據接收方返回的數據

         //根據序號排序發送給設備

           save(resultData,deviceNo,blockNumber);

             blockNumber = (byte) ((++blockNumber) % 256);
             result=null;
          }
          inputStream.close();
       } catch (Exception e) {

      log.error("{保存升級數據錯誤}");

           //其他業務處理

       } 

   } 

注意:上面方式中的byteToCrcNum這個方式是用於計算他們的CRC16的效驗,將16進制字符串轉成字節數組計算CRC16的效驗碼。

 private String byteToCrcNum(String HexStr){
String listStr=HexStr.replaceAll(" ","")
byte[] data=HexUtil.HexString2Bytes(listStr);
  Long checkNumCrc=new CRC16().calcCRC(data);
String HexNum=Long.toHexString(checkNumCrc);
 
return padLeft(HexNum,4).toUpperCase();//不足4位的左邊自動補充0
   }

至於收到接收端以後發送數據寫到mina的Handler類裏面去。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章