How to discard data as it is sent with boost::asio?

后端 未结 1 1568
萌比男神i
萌比男神i 2020-12-17 03:41

I\'m writing some code that reads and writes to serial device using boost::asio class. However, when sending several strings between programs, I\'ve noticed tha

1条回答
  •  生来不讨喜
    2020-12-17 04:11

    Boost.Asio does not provide a higher-level abstraction for flushing a serial port's buffers. However, this can often be accomplished by having platform specific calls, such as tcflush() or PurgeComm(), operate on a serial port's native_handle().

    Each serial port has a receive and transmit buffer, and flushing operates on one or both of the buffers. For example, if two serial ports are connected (/dev/pts/3 and /dev/pts/4), and program A opens and writes to /dev/pts/3, then it can only flush the buffers associated with /dev/pts/3 (data received on /dev/pts/3 but not read, and data written to /dev/pts/3 but not transmitted). Therefore, if program B starts, opens /dev/pts/4, and wants to read non-stale data, then program B needs to flush the receive buffer for /dev/pts/4 after opening the serial port.


    Here is a complete example running on CentOs. When the example runs as a writer, it will write a sequentially increasing number to the serial port once a second. When the example runs as a writer, it will read five numbers, sleep for 5 seconds and flush its read buffer every other iteration:

    #include 
    #include 
    #include 
    #include 
    
    /// @brief Different ways a serial port may be flushed.
    enum flush_type
    {
      flush_receive = TCIFLUSH,
      flush_send = TCOFLUSH,
      flush_both = TCIOFLUSH
    };
    
    /// @brief Flush a serial port's buffers.
    ///
    /// @param serial_port Port to flush.
    /// @param what Determines the buffers to flush.
    /// @param error Set to indicate what error occurred, if any.
    void flush_serial_port(
      boost::asio::serial_port& serial_port,
      flush_type what,
      boost::system::error_code& error)
    {
      if (0 == ::tcflush(serial_port.lowest_layer().native_handle(), what))
      {
        error = boost::system::error_code();
      }
      else
      {
        error = boost::system::error_code(errno,
            boost::asio::error::get_system_category());
      }
    }
    
    /// @brief Reads 5 numbers from the serial port, then sleeps for 5 seconds,
    ///        flushing its read buffer every other iteration.
    void read_main(boost::asio::serial_port& serial_port)
    {
      std::vector buffer(5);
      for (bool flush = false;; flush = !flush)
      {
        std::size_t bytes_transferred =
            read(serial_port, boost::asio::buffer(buffer));
        for (std::size_t i = 0; i < bytes_transferred; ++i)
          std::cout << static_cast(buffer[i]) << " ";
        boost::this_thread::sleep_for(boost::chrono::seconds(5));
        if (flush)
        {
          boost::system::error_code error;
          flush_serial_port(serial_port, flush_receive, error);
          std::cout << "flush: " << error.message() << std::endl;
        }
        else
        {
          std::cout << "noflush" << std::endl;
        }
      }
    }
    
    /// @brief Write a sequentially increasing number to the serial port
    ///        every second.
    void write_main(boost::asio::serial_port& serial_port)
    {
      for (unsigned char i = 0; ; ++i)
      {
        write(serial_port, boost::asio::buffer(&i, sizeof i));
        boost::this_thread::sleep_for(boost::chrono::seconds(1));
      }
    }
    
    int main(int argc, char* argv[])
    {
      boost::asio::io_service io_service;
      boost::asio::serial_port serial_port(io_service, argv[2]);
      if (!strcmp(argv[1], "read"))
        read_main(serial_port);
      else if (!strcmp(argv[1], "write"))
        write_main(serial_port);
    }
    

    Create virtual serial ports with socat:

    $ socat -d -d PTY: PTY:
    2014/03/23 16:22:22 socat[12056] N PTY is /dev/pts/3
    2014/03/23 16:22:22 socat[12056] N PTY is /dev/pts/4
    2014/03/23 16:22:22 socat[12056] N starting data transfer loop with
                                     FDs [3,3] and [5,5]
    

    Starting both the read and write examples:

    $ ./a.out read /dev/pts/3 & ./a.out write /dev/pts/4
    [1] 12238
    0 1 2 3 4 noflush
    5 6 7 8 9 flush: Success
    14 15 16 17 18 noflush
    19 20 21 22 23 flush: Success
    28 29 30 31 32 noflush
    33 34 35 36 37 flush: Success
    

    As demonstrating in the output, numbers are only skipped in the sequence when the reader flushes its read buffer: 3 4 noflush 5 6 7 8 9 flush 14 15.

    0 讨论(0)
提交回复
热议问题