【问题标题】:Boost TCP server crash when client disconnects while server performs asio::write operation当服务器执行 asio::write 操作时客户端断开连接时提升 TCP 服务器崩溃
【发布时间】:2015-08-06 12:47:40
【问题描述】:

只是为了测试我的服务器,我从客户端使用 for 循环创建了 100 个请求,当我的服务器正在为第 N 个请求编写响应时,我故意从客户端按下 control+c,就是这样。尽管我尝试使用新连接进行连接,但服务器停止并且没有响应,任何人都可以建议我如何使我的服务器稳定并免受此类中断的影响。 这是我的服务器:

class tcp_server
 {
 public:

 tcp_server(boost::asio::io_service& io_service)
   : acceptor_(io_service, tcp::endpoint(tcp::v4(), 2020))
 {
    start_accept();
 }

 private:

 void start_accept()
 {
    tcp_connection::pointer new_connection =
        tcp_connection::create(acceptor_.get_io_service());

    acceptor_.async_accept(new_connection->socket(),
        boost::bind(&tcp_server::handle_accept, this, new_connection,
        boost::asio::placeholders::error));
 }

 void handle_user_read(const boost::system::error_code& err,
    std::size_t bytes_transferred)
 {
 }


 void handle_accept(tcp_connection::pointer new_connection,
    const boost::system::error_code& error)
 {
    if (!error)
    {
       new_connection->start();
       start_accept();
    }

 }
 tcp::acceptor acceptor_;
 };

这是我的 tcp 连接:

class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
 {
   public:

   typedef boost::shared_ptr<tcp_connection> pointer;

   static pointer create(boost::asio::io_service& io_service)
   {
      return pointer(new tcp_connection(io_service));
   }

   tcp::socket& socket()
   {
      return socket_;
   }

   void start()
   {
      // Start reading messages from the server
      start_read();

   }

   public:

   tcp_connection(boost::asio::io_service& io_service) : socket_(io_service),timer_(io_service), io(io_service),timer2_(io_service)
   {
          }


   // Reading messages from the server
   void start_read()
   {
          boost::asio::async_read(socket_, input_buffer_,
          boost::asio::transfer_at_least(1),
          boost::bind(&tcp_connection::handle_read, shared_from_this(),
          boost::asio::placeholders::error));
          timer_.expires_from_now(boost::posix_time::seconds(120));
          timer_.async_wait(boost::bind(&tcp_connection::close, shared_from_this()));

   }
   void close()
  {
    cout<<"I didn't hear the client yet:closing the socket......"<<endl;
    socket_.close();
  }


   // When stream is received, handle the message from the client
  int handle_read(const boost::system::error_code& ec)
   {

      if (!ec)
      {

          std::istream is(&input_buffer_);
          std::string line;
          std::getline(is, line);
          messageFromClient_+=line;
          messageFromClient_.erase(std::remove(messageFromClient_.begin(), messageFromClient_.end(), '\n'), messageFromClient_.end());
          std::size_t found = messageFromClient_.find('\0');
          if(found==std::string::npos)
          {
          boost::asio::async_read(socket_, input_buffer_,
          boost::asio::transfer_at_least(1),
          boost::bind(&tcp_connection::handle_read, shared_from_this(),
          boost::asio::placeholders::error));
          }
          else{
            performmaj();--my logic never mind.
            std::cout << "Request: "<<i<<" is on process......"<<"\n";--mylogic 
            boost::asio::ip::tcp::no_delay option(true);
            socket_.set_option(option);
            write();
            messageToClient_="";--my logic.
            boost::system::error_code tc;
            socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_send, tc);
            }
            std::cout << "Request: "<<i<<" completed"<<"\n";
            ++i;
(boost::asio::io_service io);
          }else
       {
        std::cout << "Error on receive: " << ec.message() << "\n";
       }

   }

void write()
{
    try{
    boost::asio::write(socket_,boost::asio::buffer(messageToClient_), boost::asio::transfer_at_least(messageToClient_.size()));
    }catch(exception e)
    {
        cout<<e.what()<<endl;
        socket_.close();
        io.run();
    }

}

请查看我使用 async_write 的以下代码;请注意我打算写的字符串大小为:11279204。但是在下面的代码中使用 async_write 可以让我的客户收到更多的部分但不完整的测量。

class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
 {
   public:

   typedef boost::shared_ptr<tcp_connection> pointer;

   static pointer create(boost::asio::io_service& io_service)
   {
      return pointer(new tcp_connection(io_service));
   }

   tcp::socket& socket()
   {
      return socket_;
   }

   void start()
   {
      // Start reading messages from the server
      start_read();

   }

   public:

   tcp_connection(boost::asio::io_service& io_service) : socket_(io_service),timer_(io_service), io(io_service),timer2_(io_service)
   {
       //io=io_service;
   }


   // Reading messages from the server
   void start_read()
   {
          boost::asio::async_read(socket_, input_buffer_,
          boost::asio::transfer_at_least(1),
          boost::bind(&tcp_connection::handle_read, shared_from_this(),
          boost::asio::placeholders::error));
          timer_.expires_from_now(boost::posix_time::seconds(120));
          timer_.async_wait(boost::bind(&tcp_connection::close, shared_from_this()));

   }
   void close()
  {
    cout<<"I didn't hear the client yet:closing the socket......"<<endl;
    socket_.close();
  }


   // When stream is received, handle the message from the client
  int handle_read(const boost::system::error_code& ec)
   {

      if (!ec)
      {

          std::istream is(&input_buffer_);
          std::string line;
          std::getline(is, line);
          messageFromClient_+=line;
          messageFromClient_.erase(std::remove(messageFromClient_.begin(), messageFromClient_.end(), '\n'), messageFromClient_.end());
          std::size_t found = messageFromClient_.find('\0');
          if(found==std::string::npos)
          {
          boost::asio::async_read(socket_, input_buffer_,
          boost::asio::transfer_at_least(1),
          boost::bind(&tcp_connection::handle_read, shared_from_this(),
          boost::asio::placeholders::error));
          }
          else{
            performmaj();
            cout<<messageToClient_.size()<<endl;--11279204
              try{
            boost::asio::async_write(socket_, boost::asio::buffer(messageToClient_.data(),messageToClient_.size()),
           // boost::asio::transfer_at_least(messageToClient_.size()),
            boost::bind(&tcp_connection::handle_write, shared_from_this(),
            boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
            }catch(exception e)
            {
                Shutdown();
            }
            }
            std::cout << "Request: "<<i<<" completed"<<"\n";
            ++i;
            return 0;

          }else
       {
        std::cout << "Error on receive: " << ec.message() << "\n";
       }

   }

 void Shutdown()
  {
    try {
      socket_.shutdown(socket_.shutdown_both);
      socket_.close();
    } catch (std::exception &e)
    {
      std::cout << "Error Closing Socket" << e.what() << std::endl;
    }
  }

void performmaj()
 {
    std::size_t found = messageFromClient_.find('\0');
    if (found!=std::string::npos)
    {
            std::cout << "Request: "<<i<<" Recieved"<<"\n";
            std::cout << "Request: "<<i<<" is on process......"<<"\n";
            if (messageFromClient_.size () > 0) messageFromClient_.resize (messageFromClient_.size () - 1);
            messageToClient_=test(messageFromClient_);
            messageFromClient_="";
            messageToClient_.erase(std::remove(messageToClient_.begin(), messageToClient_.end(), '\n'), messageToClient_.end());

     }

 }

   void handle_write(const boost::system::error_code& ec,
     size_t bytes_transferred)
   {
            boost::asio::async_write(socket_,boost::asio::buffer(messageToClient_.data(),bytes_transferred),
           // boost::asio::transfer_at_least(bytes_transferred),
            boost::bind(&tcp_connection::handle_write, shared_from_this(),
            boost::asio::placeholders::error,
            bytes_transferred));
            boost::system::error_code tc;
            socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_send, tc);


   }
   tcp::socket socket_;
   std::string messageToClient_;
   boost::asio::streambuf input_buffer_;
   std::string messageFromClient_;
   boost::asio::io_service& io;
   boost::asio::deadline_timer timer_,timer2_;

 };

上述 async_write 的意外行为导致我使用 asio::write。

【问题讨论】:

  • 你为什么不使用boost::asio::async_write?您还应该查看 boost asio 文档中的chat example
  • 感谢您的回复!我试过了,问题是我一直在写我认为 asyn_write 无法处理的大量数据,因为客户端只收到了部分数据,这就是我使用 asio::write it write the data completey 的原因。
  • 我怀疑async_write 不能处理所说的“巨大”数据;您应该为客户端和发件人提供Minimal, Complete, and Verifiable example
  • 在我体验到我的代码中的 asyn_write 没有写入大量数据后,我通过一些谷歌搜索并在此链接stackoverflow.com/questions/9432722/… 中找到了一些答案,毕竟我遵循了中告诉的步骤上面的链接并在我的代码中做了一些必要的更改。但是我的客户只收到了部分数据然后我再次开始在谷歌搜索我发现 asio::write 确保它仅在所有数据都写入客户端时返回处理程序并且它执行它所说的我的客户端接收到完整数据。
  • 还有一个问题是无论如何我可以为 asio::write 设置超时选项。强制关闭套接字并使服务器在挂断时可用于接受下一个请求,

标签: c++ boost tcp boost-asio blocking


【解决方案1】:

boost::asio::write() 会阻塞,直到数据被写入或抛出异常。您的 write() 函数捕获异常,关闭套接字并返回,但并不表示套接字已关闭。然后在关闭的套接字上调用 shutdown。创建关机功能。在 write() 中捕获 drop 异常错误,但在 Write() 调用后等待调用 Shutdown。您的逻辑总是在写入好或坏时调用 Shutdown()。也不要调用 io.run()。你的 io_service() 已经在运行了。

  Shutdown()
  {
    try {
      socket_.shutdown(socket_.shutdown_both);
      socket_->close();
    } catch (std::exception &e)
    {
      std::cout << "Error Closing Socket" << e.what() << std::endl;
    }
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-28
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 2020-07-21
    • 1970-01-01
    • 2021-08-12
    • 1970-01-01
    相关资源
    最近更新 更多