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

5

为了测试我的服务器,我使用客户端循环创建了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。


1
为什么不使用boost::asio::async_write?您还应该查看Boost Asio文档中的聊天示例 - m.s.
1
我怀疑async_write无法处理所谓的“巨大”数据;你应该为客户端和发送方提供一个最小、完整和可验证的示例 - m.s.
1
总之,如果您需要超时和可取消性,则建议使用异步方法。 - m.s.
1
如果你想让async_write正常工作,你需要编辑你的问题并为服务器和客户端提供一个最小、完整且可验证的示例;如果没有这个,没有人能够帮助你解决问题。 - m.s.
明天会做,目前我没有代码,但我做的是常见的async_write和它的处理程序。在其中又有一个async_write,从我的角度来看这没有问题,它可以正常工作,但它没有发送完整的数据,尽管已经从async_write递归到处理程序,然后从处理程序到async_write。 - RaGa__M
显示剩余5条评论
1个回答

2

boost::asio::write()函数会阻塞,直到数据被写入或者抛出异常。你的write()函数捕获异常、关闭socket并返回,但是没有指示socket已经关闭。然后你调用了一个已经关闭的socket上的shutdown()函数。创建一个Shutdown函数,在Write()调用后捕获drop exception error,但是等待调用Write()后再调用Shutdown。你的逻辑总是在good或bad writes时调用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;
    }
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接