当服务器执行 asio::write 操作时客户端断开连接时,Boost TCP 服务器崩溃

RaG*_*__M 5 c++ boost tcp blocking boost-asio

为了测试我的服务器,我从客户端使用 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_;
 };
Run Code Online (Sandbox Code Playgroud)

这是我的 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();
    }

}
Run Code Online (Sandbox Code Playgroud)

请参阅下面的代码,其中我使用了 async_write;请注意,我打算写入的字符串大小为:11279204。但在下面的代码中使用 async_write 让我的客户收到更多部分但不完整的meaasage。

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_;

 };
Run Code Online (Sandbox Code Playgroud)

上述 async_write 的不可预测行为导致我使用 asio::write 。

小智 2

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;
    }
  }
Run Code Online (Sandbox Code Playgroud)