【问题标题】:async_ read_until doesn't work as expectedasync_ read_until 没有按预期工作
【发布时间】:2015-11-18 23:19:15
【问题描述】:

所以我正在尝试编写一个通过 tcp 套接字读取和写入数据的程序。我可以成功接受连接,向其写入数据(尽管写入处理程序没有按预期工作?)。我也想通过同一个套接字读取数据——这似乎不起作用。 处理这一切的类如下:

using namespace boost::asio;
using namespace boost::asio::ip;


TcpServer::TcpServer(unsigned short port = 1700)
  : ipPort(port){
  tcp::acceptor acc(svc, tcp::endpoint(tcp::v4(), ipPort));
  acc.listen();
  acc.async_accept(socket, boost::bind(&TcpServer::Accept_Handler,this, placeholders::error));

  SAY("Waiting for a New connection");
  svc.run();
}

void TcpServer::Write_Handler(const boost::system::error_code& ec,
                  std::size_t bytes_transferred){
  std::cout << ec.message() << std::endl;
  if (!ec)
    {
      std::cout << "Just sent " << yawData << std::endl;
    }
}
void TcpServer::Read_Handler(const boost::system::error_code& ec,
                std::size_t bytes_transferred){
  if (!ec)
    {
      std::string line;
     std::istream is(&input_buffer_);
     std::string test;
     is >> test;
     std::cout << "test" << test << std::endl;
     std::getline(is, line);
     if (!line.empty())
       {
     std::cout << "Recieved: " << line << std::endl;
       }
    }
  else
    std::cout << "Error reading:" << ec.message() << std::endl;
}

void TcpServer::Accept_Handler(const boost::system::error_code& ec){
  if (!ec)
    {
      std::cout << "Accepted a connection! - Now switching to write mode " << std::endl;
  connectMode = 1;
    }
}

void TcpServer::Write_Data(){
  if (connectMode){
    SAY("Sent data");
    std::ostringstream ss;
    std::string sendBuffer;
    ss << std::fixed << std::setprecision(2);
    ss << yawData;
    sendBuffer = ss.str() + "\r";
    async_write(socket, buffer(sendBuffer),       boost::bind(&TcpServer::Write_Handler, this,
                      placeholders::error,
                       placeholders::bytes_transferred));
    }
}


void TcpServer::UpdateYaw(double data) {
  yawData = data;
}  

void TcpServer::Read_Data(){
  if (connectMode){
    async_read_until(socket, input_buffer_, "\n" ,      boost::bind(&TcpServer::Read_Handler, this,
                          placeholders::error,
                               placeholders::bytes_transferred));
  }
}

TcpServer::~TcpServer(){
   svc.stop();
}

类头如下:

class TcpServer {
 private:
  io_service svc;  
  tcp::socket socket{svc};

  double yawData = 0;
  unsigned short ipPort;
  bool connectMode = 0;
  streambuf input_buffer_;
  void Write_Handler(const boost::system::error_code&,
             std::size_t);
  void Read_Handler(const boost::system::error_code&,
             std::size_t);
   void Accept_Handler(const boost::system::error_code&);
 public:
  TcpServer(unsigned short );
  void Write_Data();
  void Read_Data();
  void UpdateYaw(double);
  ~TcpServer();
};

要使用它,我调用 Write_Data(),然后调用 Read_Data()。 Write_Data 有效,但未调用写入处理程序 - 我可以在客户端接收数据。 Read_Data() 根本不起作用。我确定数据正在通过套接字以所需的格式发送(以“\n”结尾)

关于可能出错的任何想法或任何调试提示?

谢谢

编辑

我计划从我的 main 函数中运行 write_data 和 read_data 函数,如下所示:

  TcpServer *socketObj = new TcpServer(1700);

     while ( i < 100 && trackObj->ReadTrackingState() != 0) {
      SAY("Current Yaw - %.02f", trackObj->CurrentYaw());
      socketObj->UpdateYaw(trackObj->CurrentYaw());
      socketObj->Write_Data();
      socketObj->Read_Data();
      Platform::sleepMillis(1000);
      i++;

     }

【问题讨论】:

    标签: string sockets boost tcp boost-asio


    【解决方案1】:
    void TcpServer::Accept_Handler(const boost::system::error_code &ec) {
        if (!ec) {
            std::cout << "Accepted a connection! - Now switching to write mode " << std::endl;
            connectMode = 1;
        }
    }
    

    此函数结束异步处理。它不再安排任何异步工作,因此io_service::run() 结束,如文档所述。

    您想直接链接或使用io_service::work 来保持服务运行。我建议链接:

    void TcpServer::Accept_Handler(const boost::system::error_code &ec) {
        if (!ec) {
            std::cout << "Accepted a connection! - Now switching to write mode " << std::endl;
            Write_Data();
        }
    }
    

    但是……

    按住

    您需要仔细查看所有代码。

    void TcpServer::Write_Data() {
        SAY("Sent data");
        std::ostringstream ss;
        std::string sendBuffer;
        ss << std::fixed << std::setprecision(2);
        ss << yawData;
        sendBuffer = ss.str() + "\r";
        async_write(socket, buffer(sendBuffer),
                boost::bind(&TcpServer::Write_Handler, this, placeholders::error, placeholders::bytes_transferred));
    }
    

    这里发生了什么?首先,您创建一个临时流,未能使用它来附加回车,然后将对本地字符串的引用传递给async_write...这是行不通的。我是Undefined Behaviour

    修复:

    void TcpServer::Write_Data() {
        SAY("Send data");
        std::ostream ss(&output_buffer_);
        ss << std::fixed << std::setprecision(2) << yawData << "\r";
        async_write(socket, output_buffer_,
                boost::bind(&TcpServer::Write_Handler, this, placeholders::error, placeholders::bytes_transferred));
    }
    

    演示

    Live On Coliru

    #include <boost/asio.hpp>
    #include <boost/bind.hpp>
    #include <iostream>
    #include <iomanip>
    
    using namespace boost::asio;
    using namespace boost::asio::ip;
    
    template <typename T>
    static inline void SAY(T&& v) { std::cout << std::forward<T>(v) << "\n"; }
    
    class TcpServer {
      private:
        io_service svc;
        tcp::socket socket{ svc };
    
        double yawData = 0;
        unsigned short ipPort;
        streambuf input_buffer_, output_buffer_;
    
        void Write_Handler(const boost::system::error_code &, std::size_t);
        void Read_Handler(const boost::system::error_code &, std::size_t);
        void Accept_Handler(const boost::system::error_code &);
    
      public:
        TcpServer(unsigned short = 1700);
        void Write_Data();
        void Read_Data();
        void UpdateYaw(double);
        ~TcpServer();
    };
    
    TcpServer::TcpServer(unsigned short port) : ipPort(port) {
        tcp::acceptor acc(svc, tcp::endpoint(tcp::v4(), ipPort));
        acc.listen();
        acc.async_accept(socket, boost::bind(&TcpServer::Accept_Handler, this, placeholders::error));
    
        SAY("Waiting for a New connection");
        svc.run();
    }
    
    void TcpServer::Write_Handler(const boost::system::error_code &ec, std::size_t /*bytes_transferred*/) {
        std::cout << ec.message() << std::endl;
        if (!ec) {
            std::cout << "Just sent " << yawData << std::endl;
            Read_Data();
        }
    }
    void TcpServer::Read_Handler(const boost::system::error_code &ec, std::size_t /*bytes_transferred*/) {
        if (!ec) {
            std::cout << "Recieved: " << &input_buffer_ << std::endl;
        } else
            std::cout << "Error reading:" << ec.message() << std::endl;
    }
    
    void TcpServer::Accept_Handler(const boost::system::error_code &ec) {
        if (!ec) {
            std::cout << "Accepted a connection! - Now switching to write mode " << std::endl;
            Write_Data();
        }
    }
    
    void TcpServer::Write_Data() {
        SAY("Send data");
        std::ostream ss(&output_buffer_);
        ss << std::fixed << std::setprecision(2) << yawData << "\r";
        async_write(socket, output_buffer_,
                boost::bind(&TcpServer::Write_Handler, this, placeholders::error, placeholders::bytes_transferred));
    }
    
    void TcpServer::UpdateYaw(double data) { yawData = data; }
    
    void TcpServer::Read_Data() {
        async_read_until(socket, input_buffer_, "\n", boost::bind(&TcpServer::Read_Handler, this, placeholders::error,
                    placeholders::bytes_transferred));
    }
    
    TcpServer::~TcpServer() { svc.stop(); }
    
    int main() {
        TcpServer server;
    }
    

    【讨论】:

    • 非常感谢!这是精彩而详细的。我没有链接它们的原因是,我从另一个文件的主函数循环调用了 Write_Data() 和 Read_Data()。就像你解释的那样 - 因为服务不再存在,所以这不起作用。有没有办法我仍然可以做到这一点?我已经编辑了问题以添加我计划如何进行通信。我有点迷失在文档上。
    • 使用io_service::work 或考虑将spawn 与协同程序一起使用
    猜你喜欢
    • 2021-10-19
    • 2020-03-18
    • 2012-06-14
    • 2014-11-15
    • 1970-01-01
    • 2012-07-02
    • 2011-09-07
    • 2013-03-03
    • 2015-05-18
    相关资源
    最近更新 更多