从streambuffer中提升异步读写异常数据

Boost asynchronous read and write weird data from streambuffer

本文关键字:读写 异常 数据 异步 streambuffer      更新时间:2023-10-16

我正在使用boost异步读写我的微控制器。我安装了我的微控制器,这样它就可以读取异步写入发送的数据,并将其返回到计算机,在计算机中,计算机通过单个线程上的异步读取来读取数据。我把"15"发送到微控制器。插入微控制器后的每次第一次发送都工作良好,但在此之后,它会偶尔从串行端口"f"answers"?f15"读取"。无论何时f或?f15被发送,7个字节在回调中被传输,这对我来说意义不大,因为f只是一个ascii值。这是我的客户端串行端口包装代码:

void Serial::async_write(std::string string){
std::cout << "String size:" << string.size() << std::endl;
// char stringToChar[string.size() + 1];
// strcpy(stringToChar, string.c_str());
// this->async_write(stringToChar);
boost::asio::async_write(*port_, boost::asio::buffer(string, string.length()), boost::bind(&Serial::async_write_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void Serial::async_write_buffer(std::vector<char> data){
int num = data.size();
std::cout << num << std::endl;
boost::asio::mutable_buffer buf(&data, data.size());
boost::asio::async_write(*port_, boost::asio::buffer(data, data.size()), boost::bind(&Serial::async_write_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void Serial::async_write_handler(const boost::system::error_code &e, std::size_t bytes_written){
std::cout << "Data written" << std::endl;
//b_->consume(bytes_written);
}
void Serial::async_read_handler(const boost::system::error_code &e, std::size_t bytes_read){
if(!(*e)){
std::cout << "bytes read in async read handler:" << bytes_read << std::endl;
if(bytes_read > 0){
b_->commit(bytes_read);
std::istream* instream = new std::istream(b_);
std::string streamtostring;
*instream >> streamtostring;
std::cout << "size of input buffer:" << b_->size() << std::endl;
std::cout << "Read: " <<std::endl;
b_->consume(bytes_read);
std::cout << streamtostring << std::endl;
}
else{
std::cout << "No bytes read" << std::endl;
}
}
else{
std::cout << "Error occurred!" << std::endl;
std::cerr << e.message() << std::endl;
}
}
void Serial::async_read_until(std::string delim){
boost::system::error_code e;
boost::asio::async_read_until(*port_, *b_, delim, boost::bind(&Serial::async_read_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

这是在main.cpp中调用它的代码:

int main(){
boost::asio::io_service io;
Serial::Serial serial(PORT, &io, 9600);
if(!serial.is_open()){
serial.open(PORT);
}
std::string s = "15";
serial.async_write(s);
serial.async_read_until("n");
// const char arr[] = {'2', '5', '5'};
// serial.async_write(arr);
// std::string s = "50089q503320232500202";
// std::vector<char> data(s.begin(), s.end());
// serial.async_write_buffer(data);
io.run();
}

现在在微控制器方面,我让它将每个传入的数据字节放入一个字符的stackArray中,然后将它们一个接一个地弹出到一个比堆栈数组多1个字符长的字符数组中。由于异步读取一直读到换行符,所以我在字符数组的最后插入一个换行符。然后我把它送过小溪。

#include <StackArray.h>
StackArray<int> binary;
int ledPin = 13;
int numberOfExecs = 0;
byte data = 0;
void setup() {
Serial.begin(9600);
//binary.setPrinter(Serial);
pinMode(ledPin, OUTPUT);
}
void blink(int times, int duration){
for(int i = 0; i < times; i++){
digitalWrite(ledPin, HIGH);
delay(duration);
digitalWrite(ledPin, LOW);
delay(duration);
}
}
void loop() {
//get number of bytes waiting in the serial buffer
int bytesWaiting = Serial.available();
//create array of character values
StackArray<char> letterVals;
//Set the printer for the stack array to serial
letterVals.setPrinter(Serial);
//while serial is available, push each byte of data to the stack array
while(Serial.available() > 0){
byte data = Serial.read();
char c = data;
//Serial.println(c);
letterVals.push(c);
//    convertToBinary(data, binary);
//    printToLED(binary);
}
//Get the number of elements in the stack array
int numElements = letterVals.count();
//indicate how many elements there are on the led
blink(numElements, 1000);
// blink(1, 5000);
//length of array
int len = numElements + 1;
//create array to send back data
char sendback[len];
if(bytesWaiting > 0){
for(int i = len - 2; i >= 0; i--){
//pop each character into its original position
int asciiVal = letterVals.pop();
//blink(asciiVal, 350);
//blink(20, 20);
sendback[i] = asciiVal;
}
}
//set last character to newline
sendback[len - 1] = 10;
//if there are no bytes available to read, send off data
if(bytesWaiting > 0){  
Serial.println(sendback);
}
}

有人知道为什么随机f和吗?f一直出现吗?谢谢

这可能是客户端代码调用未定义行为的结果。具体来说,该代码无法满足boost::asio::async_write()buffers参数的生存期要求

[…]底层内存块的所有权由调用者保留,调用者必须保证它们在调用处理程序之前保持有效。

Serial::async_write()Serial::async_write_buffer()中,作为缓冲区提供的底层内存由一个对象所有,该对象的生存期在函数返回后结束。由于这两个函数都不能保证它们在调用async_write的完成处理程序之前不会返回,因此临时函数的生存期违反了async_write()的要求,导致了未定义的行为。

void Serial::async_write(std::string string)
{
boost::asio::async_write(
...,
boost::asio::buffer(string, string.length()),
...);
} // `string`'s lifetime ends.
void Serial::async_write_buffer(std::vector<char> data)
{
boost::asio::async_write(
...,
boost::asio::buffer(data, data.size()),
...);
} // `data`'s lifetime ends.