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

时间:2015-08-06 12:47:41

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

为了测试我的服务器,我已经使用来自客户端的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让我的客户端接收更多部分但不完整的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_;

 };

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

1 个答案:

答案 0 :(得分:1)

boost :: asio :: write()阻塞,直到写入数据或抛出异常。 write()函数捕获异常,关闭套接字并返回,但不表示套接字已关闭。然后在关闭的套接字上调用shutdown。创建关机功能。在write()中捕获丢弃异常错误但等待在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;
    }
  }