async_ read_until не работает должным образом

Поэтому я пытаюсь написать программу, которая читает и записывает данные через 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")

Любые идеи о том, что может быть не так или какие-либо советы по отладке?

Спасибо

РЕДАКТИРОВАТЬ

Я планирую запустить функции 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++;

     }

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... Это не может работать. Это неопределенное поведение.

Исправление:

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));
}

DEMO

Жить на Колиру

#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;
}
Другие вопросы по тегам