【问题标题】:Boost asynchronous read and write weird data from streambuffer从流缓冲区提升异步读写怪异数据
【发布时间】:2016-05-26 01:59:22
【问题描述】:

我正在使用 boost 对我的微控制器进行异步读写。我安装了我的微控制器,以便它读取异步写入发送的数据并将其回显到计算机,计算机通过单线程上的异步读取来读取它。我正在向微控制器发送“15”。插入微控制器后的每次第一次发送都运行良好,但在此之后它会偶尔从串行端口“f”和“?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();
}

现在在微控制器方面,我让它将每个传入的数据字节放入一个字符堆栈数组中,然后将它们一个接一个地弹出到一个字符数组中,该字符数组比堆栈数组的字符长多 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 不断出现?谢谢。

【问题讨论】:

    标签: c++ asynchronous boost boost-asio


    【解决方案1】:

    这可能是客户端代码调用未定义行为的结果。具体来说,代码无法满足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.
    

    【讨论】:

    • 代码审查 cmets:在类似缓冲区的对象中发送所有数据时,请考虑指定缓冲区大小,因为buffer() 重载会推导出大小; istream 分配在free-store上并且永远不会被删除,考虑使用自动变量; streambuf 的用法很尴尬,因为提交和消费将是无操作的(有关更多详细信息,请参阅 this 答案)。
    猜你喜欢
    • 2015-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多