一、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類裏面去。