5

Just to test my server, I've created 100 requests using a for loop from my client side and while my server is writing response for the Nth request I deliberately pressed control+c from the client, Thats it. The server stops and has gone unresponsive although I try connecting it using a new connection, can any one advice me how to make my server stable and immune to such interrupt. here is my server:

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

here is my tcp connection:

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

}

please see my below code where i have used async_write; Note the string i have intende to write is of size:11279204. but using async_write in the below code let my client to recieve the meaasage that is more of partial but not complete.

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

 };

the above unpredicted behaviour of async_write have caused me to use asio::write.

RaGa__M
  • 2,550
  • 1
  • 23
  • 44
  • 1
    why don't you use `boost::asio::async_write`? you should also have a look at the [chat example](http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/example/cpp03/chat/chat_server.cpp) in the boost asio documentation – m.s. Aug 06 '15 at 14:08
  • thank you for the reply! i tried it,the problem is i have been writing huge data which asyn_write can't handle i think,because the client recieves only partial amount of data thats why i have gone with asio::write it write the data completey. – RaGa__M Aug 06 '15 at 14:11
  • 1
    I doubt that `async_write` can't handle said "huge" data; you should provide a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) for both client and sender – m.s. Aug 06 '15 at 14:13
  • After i experienced that asyn_write in my code haven't write the huge data i have gone through some google search and find some answers in this link http://stackoverflow.com/questions/9432722/boostasioasync-write-writing-data-larger-than-65536-bytes, after all i followed the steps that told in the above link and done some necessary changes in my code . but my cliient recieved only partial data then again i started googling where i found asio::write which ensure it returns handler only when all the data has written to the client and it does what it says my client receives complete data. – RaGa__M Aug 06 '15 at 14:20
  • And one more question is there anyway i can have timeout option for asio::write. do force closing of socket and make the server available for accepting next request when it hungs up, – RaGa__M Aug 06 '15 at 14:37
  • 1
    ["To summarize, it is suggested to use asynchronous methods if you desire timeouts and cancellability."](http://stackoverflow.com/questions/4553162/c-boost-asio-how-to-read-write-with-a-timeout) – m.s. Aug 06 '15 at 14:49
  • Hi M.S the first write method I have used is async_write but I don't have any idea why my data can't completely written to client, do you have any suggestions about this async_write behavior, I also used the completion condition like transfer_all() inside the write but got the same, so at last I have decided to go by asio::write. – RaGa__M Aug 06 '15 at 16:38
  • The documentation you have pointed gives useful info, but I just need any exception handling tricks that will catch any strange abort or interrupt from the client throw it away and keep the server listening without any hanging. – RaGa__M Aug 06 '15 at 16:44
  • 1
    if you want `async_write` to work, you need to edit your question and provide a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) for both server and client; without that, nobody will be able to help you with that – m.s. Aug 06 '15 at 16:46
  • Will do in the morning,currently I don't have the code but what I did is. The common async_write and it's handler where I am again have async_write inside it no problem with that from my concern.it works but not send the complete data though it has been called recursively from async_write to handler and handler to async_write. – RaGa__M Aug 06 '15 at 17:18

1 Answers1

2

The boost::asio::write() blocks until the data is written or an exception is thrown. Your write() function catches the exception, closes the socket, and returns, but does not indicate the socket is closed. You then call shutdown on a closed socket. Create a Shutdown function. Catch the drop exception error in write() but wait to call Shutdown after Write() call. Your logic always calls Shutdown() on good or bad writes. Also do not call io.run(). Your io_service() is already running.

  Shutdown()
  {
    try {
      socket_.shutdown(socket_.shutdown_both);
      socket_->close();
    } catch (std::exception &e)
    {
      std::cout << "Error Closing Socket" << e.what() << std::endl;
    }
  }
user207421
  • 305,947
  • 44
  • 307
  • 483
sfanjoy
  • 640
  • 6
  • 16