我正在從串行設備中讀取每個消息必須特別請求的地方。例如。您發送請求並獲得序列化有效負載的響應。如何在連續讀取async_read_until後使用asio緩衝區
每個消息包含在順序包括以下部分:
- 前導碼(2個字節, 「$ M」)
- HEADER(3個字節,包含有效載荷長度N)
- PAYLOAD + CRC(N + 1個字節)
我與ASIO的方法是通過使用asio::async_read_until
事後使用asio::async_read
用於讀取的字節的確切的量對於HEADER以檢測消息的開始(前同步碼),並PAYLOAD + CRC。由於消息末尾沒有靜態模式,因此我無法使用async_read_until
來閱讀完整消息。
收到PREAMBLE後,async_read_until
的處理程序被調用,緩衝區包含PREAMBLE字節,並可能包含來自HEADER和PAYLOAD + CRC的附加字節。 爲async_read_until的ASIO文件說:
成功async_read_until操作後,流緩衝可以 含有超出分隔符附加數據。應用程序 通常將該數據保留在streambuf中以供隨後的async_read_until操作檢查。
我解釋這是因爲你應該只消耗請求的字節,並將所有剩餘的字節留在緩衝區中作進一步讀取。 但是,由於數據已經存在於緩衝區中並且設備上沒有任何內容,因此所有連續的讀取塊都將被阻止。
該讀取是作爲小型狀態機processState
實現的,其中根據要讀取的消息的哪一部分來註冊不同的處理程序。所有讀數都使用相同的buffer
(asio::streambuf
)完成。在無限循環中調用processState
。
void processState() {
// register handler for incomming messages
std::cout << "state: " << parser_state << std::endl;
switch (parser_state) {
case READ_PREAMBLE:
asio::async_read_until(port, buffer, "$M",
std::bind(&Client::onPreamble, this, std::placeholders::_1, std::placeholders::_2));
break;
case READ_HEADER:
asio::async_read(port, buffer, asio::transfer_exactly(3),
std::bind(&Client::onHeader, this, std::placeholders::_1, std::placeholders::_2));
break;
case READ_PAYLOAD_CRC:
asio::async_read(port, buffer, asio::transfer_exactly(request_received->length+1),
std::bind(&Client::onDataCRC, this, std::placeholders::_1, std::placeholders::_2));
break;
case PROCESS_PAYLOAD:
onProcessMessage();
break;
case END:
parser_state = READ_PREAMBLE;
break;
}
// wait for incoming data
io.run();
io.reset();
}
序言處理器onPreamble
接收到前導時,被稱爲:
void onPreamble(const asio::error_code& error, const std::size_t bytes_transferred) {
std::cout << "onPreamble START" << std::endl;
if(error) { return; }
std::cout << "buffer: " << buffer.in_avail() << "/" << buffer.size() << std::endl;
// ignore and remove header bytes
buffer.consume(bytes_transferred);
std::cout << "buffer: " << buffer.in_avail() << "/" << buffer.size() << std::endl;
buffer.commit(buffer.size());
std::cout << "onPreamble END" << std::endl;
parser_state = READ_HEADER;
}
此處理後,沒有其他的處理程序被調用,因爲數據是在緩衝區中,沒有數據留在設備上。
使用asio::streambuf
的正確方法是什麼,使得調用連續的async_read
的處理程序並且我可以按照狀態機的順序處理字節?我不想處理onPreamble
中的剩餘字節,因爲不能保證這些字節將包含完整的消息。