国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|

服務器之家 - 編程語言 - JAVA教程 - 使用java實現Xmodem協議

使用java實現Xmodem協議

2020-07-15 12:08容華謝后 JAVA教程

這篇文章主要介紹了使用java實現Xmodem協議的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下

1.介紹

Xmodem是一種在串口通信中廣泛使用的異步文件傳輸協議,分為Xmodem(使用128字節的數據塊)和1k-Xmodem(使用1024字節即1k字節的數據塊)協議兩種。
本文實現的是128字節數據塊的Xmodem協議,采用CRC16校驗,在項目中應用時,發送端和接收端可根據具體情況修改雙方的協議。
如果你對串口通信還不太了解,可以看下我寫的這篇博客使用Java實現串口通信

2.實現

在和嵌入式同學調試的過程中,發現發送端發送數據過快,導致接收端處理不過來,所以在send方法中開啟了一個子線程來處理數據發送邏輯,方便加入延時處理。
接收方法中,發送C是表示以CRC方式校驗。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
public class Xmodem {
 
 // 開始
 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;
 
 // 以128字節塊的形式傳輸數據
 private final int SECTOR_SIZE = 128;
 // 最大錯誤(無應答)包數
 private final int MAX_ERRORS = 10;
 
 // 輸入流,用于讀取串口數據
 private InputStream inputStream;
 // 輸出流,用于發送串口數據
 private OutputStream outputStream;
 
 public Xmodem(InputStream inputStream, OutputStream outputStream) {
 this.inputStream = inputStream;
 this.outputStream = outputStream;
 }
 
 /**
 * 發送數據
 *
 * @param filePath
 *  文件路徑
 */
 public void send(final String filePath) {
 new Thread() {
  public void run() {
  try {
   // 錯誤包數
   int errorCount;
   // 包序號
   byte blockNumber = 0x01;
   // 校驗和
   int checkSum;
   // 讀取到緩沖區的字節數量
   int nbytes;
   // 初始化數據緩沖區
   byte[] sector = new byte[SECTOR_SIZE];
   // 讀取文件初始化
   DataInputStream inputStream = new DataInputStream(
    new FileInputStream(filePath));
 
   while ((nbytes = inputStream.read(sector)) > 0) {
   // 如果最后一包數據小于128個字節,以0xff補齊
   if (nbytes < SECTOR_SIZE) {
    for (int i = nbytes; i < SECTOR_SIZE; i++) {
    sector[i] = (byte) 0xff;
    }
   }
 
   // 同一包數據最多發送10次
   errorCount = 0;
   while (errorCount < MAX_ERRORS) {
    // 組包
    // 控制字符 + 包序號 + 包序號的反碼 + 數據 + 校驗和
    putData(SOH);
    putData(blockNumber);
    putData(~blockNumber);
    checkSum = CRC16.calc(sector) & 0x00ffff;
    putChar(sector, (short) checkSum);
    outputStream.flush();
 
    // 獲取應答數據
    byte data = getData();
    // 如果收到應答數據則跳出循環,發送下一包數據
    // 未收到應答,錯誤包數+1,繼續重發
    if (data == ACK) {
    break;
    } else {
    ++errorCount;
    }
   }
   // 包序號自增
   blockNumber = (byte) ((++blockNumber) % 256);
   }
 
   // 所有數據發送完成后,發送結束標識
   boolean isAck = false;
   while (!isAck) {
   putData(EOT);
   isAck = getData() == ACK;
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
  };
 }.start();
 }
 
 /**
 * 接收數據
 *
 * @param filePath
 *  文件路徑
 * @return 是否接收完成
 * @throws IOException
 *  異常
 */
 public boolean receive(String filePath) throws Exception {
 // 錯誤包數
 int errorCount = 0;
 // 包序號
 byte blocknumber = 0x01;
 // 數據
 byte data;
 // 校驗和
 int checkSum;
 // 初始化數據緩沖區
 byte[] sector = new byte[SECTOR_SIZE];
 // 寫入文件初始化
 DataOutputStream outputStream = new DataOutputStream(
  new FileOutputStream(filePath));
 
 // 發送字符C,CRC方式校驗
 putData((byte) 0x43);
 
 while (true) {
  if (errorCount > MAX_ERRORS) {
  outputStream.close();
  return false;
  }
 
  // 獲取應答數據
  data = getData();
  if (data != EOT) {
  try {
   // 判斷接收到的是否是開始標識
   if (data != SOH) {
   errorCount++;
   continue;
   }
 
   // 獲取包序號
   data = getData();
   // 判斷包序號是否正確
   if (data != blocknumber) {
   errorCount++;
   continue;
   }
 
   // 獲取包序號的反碼
   byte _blocknumber = (byte) ~getData();
   // 判斷包序號的反碼是否正確
   if (data != _blocknumber) {
   errorCount++;
   continue;
   }
 
   // 獲取數據
   for (int i = 0; i < SECTOR_SIZE; i++) {
   sector[i] = getData();
   }
 
   // 獲取校驗和
   checkSum = (getData() & 0xff) << 8;
   checkSum |= (getData() & 0xff);
   // 判斷校驗和是否正確
   int crc = CRC16.calc(sector);
   if (crc != checkSum) {
   errorCount++;
   continue;
   }
 
   // 發送應答
   putData(ACK);
   // 包序號自增
   blocknumber++;
   // 將數據寫入本地
   outputStream.write(sector);
   // 錯誤包數歸零
   errorCount = 0;
 
  } catch (Exception e) {
   e.printStackTrace();
 
  } finally {
   // 如果出錯發送重傳標識
   if (errorCount != 0) {
   putData(NAK);
   }
  }
  } else {
  break;
  }
 }
 
 // 關閉輸出流
 outputStream.close();
 // 發送應答
 putData(ACK);
 
 return true;
 }
 
 /**
 * 獲取數據
 *
 * @return 數據
 * @throws IOException
 *  異常
 */
 private byte getData() throws IOException {
 return (byte) inputStream.read();
 }
 
 /**
 * 發送數據
 *
 * @param data
 *  數據
 * @throws IOException
 *  異常
 */
 private void putData(int data) throws IOException {
 outputStream.write((byte) data);
 }
 
 /**
 * 發送數據
 *
 * @param data
 *  數據
 * @param checkSum
 *  校驗和
 * @throws IOException
 *  異常
 */
 private void putChar(byte[] data, short checkSum) throws IOException {
 ByteBuffer bb = ByteBuffer.allocate(data.length + 2).order(
  ByteOrder.BIG_ENDIAN);
 bb.put(data);
 bb.putShort(checkSum);
 outputStream.write(bb.array());
 }
}

CRC16校驗算法,采用的是查表法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class CRC16 {
 
 private static final char crctable[] = { 0x0000, 0x1021, 0x2042, 0x3063,
  0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b,
  0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252,
  0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a,
  0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
  0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509,
  0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630,
  0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
  0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7,
  0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af,
  0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
  0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e,
  0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5,
  0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
  0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4,
  0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc,
  0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
  0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3,
  0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da,
  0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
  0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589,
  0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481,
  0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
  0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0,
  0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f,
  0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
  0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e,
  0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16,
  0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
  0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45,
  0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c,
  0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
  0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 };
 
 public static char calc(byte[] bytes) {
 char crc = 0x0000;
 for (byte b : bytes) {
  crc = (char) ((crc << 8) ^ crctable[((crc >> 8) ^ b) & 0x00ff]);
 }
 return (char) (crc);
 }
}

3.使用

?
1
2
3
4
5
// serialPort為串口對象
Xmodem xmodem = new Xmodem(serialPort.getInputStream(),serialPort.getOutputStream());
// filePath為文件路徑
// ./bin/xxx.bin
xmodem.send(filePath);

4.寫在最后

完整的代碼下載

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://blog.csdn.net/kong_gu_you_lan/article/details/53673236

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 天堂一区二区三区 | 国产精品亚洲精品 | 亚洲精品一二三 | 中文字幕第33页 | 免费在线黄色片 | 国产一区二区三区不卡在线观看 | 国产区视频在线观看 | 北条麻妃99精品青青久久主播 | 亚洲成人av一区二区三区 | 免费在线观看一区二区 | 91五月天| 国产精品一区二区三区免费 | 日韩午夜 | 久久人人爽人人爽人人片av不 | 亚洲精品免费视频 | 视频一区中文字幕 | 午夜视频在线播放 | 91在线| 亚洲小视频 | 亚洲色图50p| 欧美日韩一区二区三区 | 都市激情在线视频 | 日日精品 | 午夜精品久久久久久久久久久久 | 成人一级黄色大片 | 午夜精品美女久久久久av福利 | 91精品视频在线播放 | 国产成人精品一区二 | 伊人激情综合网 | 一区二区 中文字幕 | 国产视频网 | 黄在线看 | 综合色成人 | 国产一区二区三区免费视频 | 91久久久久久久久久久久久久久久 | 亚洲一区二区在线视频 | 精品久久中文字幕 | 亚洲一区中文字幕 | 欧美一级在线视频 | 看av的网址| 国产精品a久久久久 |