tags:

views:

221

answers:

2

Hi,

I'm trying to figure out how asynchronous reads and writes work in boost asio by manipulating the echo example. Currently, I have a server that should, when sent a sentence, respond with only the first word. However, the boost::asio::async_write never seems to complete even though the write handler is being called. Can someone please explain what's going on? Here's the code:

#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

class session
{
public:
  session(boost::asio::io_service& io_service)
    : socket_(io_service)
  {
  }

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

  void start()
  {
 std::cout<<"starting"<<std::endl;
  boost::asio::async_read_until(socket_, buffer, ' ',
        boost::bind(&session::handle_read, this,
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
  }

  void handle_read(const boost::system::error_code& error,
      size_t bytes_transferred)
  {

// std::ostringstream ss;
// ss<<&buffer;

 char* c = new char[bytes_transferred]; 

 //std::string s;
 buffer.sgetn(c,bytes_transferred);
 std::cout<<"data: "<< c<<" bytes: "<<bytes_transferred<<std::endl;

 if (!error)
    {
      boost::asio::async_write(socket_,
          boost::asio::buffer(c,bytes_transferred),
          boost::bind(&session::handle_write, this,
            boost::asio::placeholders::error));
    }
    else
    {
      delete this;
    }
  }

  void handle_write(const boost::system::error_code& error)
  {
 std::cout<<"handling write"<<std::endl;
    if (!error)
    {
    }
    else
    {
      delete this;
    }
  }

private:
  tcp::socket socket_;
  boost::asio::streambuf buffer;
};

class server
{
public:
  server(boost::asio::io_service& io_service, short port)
    : io_service_(io_service),
      acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
  {
    session* new_session = new session(io_service_);
    acceptor_.async_accept(new_session->socket(),
        boost::bind(&server::handle_accept, this, new_session,
          boost::asio::placeholders::error));
  }

  void handle_accept(session* new_session,
      const boost::system::error_code& error)
  {
    if (!error)
    {
      new_session->start();
      new_session = new session(io_service_);
      acceptor_.async_accept(new_session->socket(),
          boost::bind(&server::handle_accept, this, new_session,
            boost::asio::placeholders::error));
    }
    else
    {
      delete new_session;
    }
  }

private:
  boost::asio::io_service& io_service_;
  tcp::acceptor acceptor_;
};

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 2)
    {
      std::cerr << "Usage: async_tcp_echo_server <port>\n";
      return 1;
    }

    boost::asio::io_service io_service;

    using namespace std; // For atoi.
    server s(io_service, atoi(argv[1]));

    io_service.run();
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

  return 0;
}

Thanks!

A: 

As a could see you just don't close the socket and even don't delete the session. After you successful write and complete write handler, you leave the session object making memory leak. Also the char* c = new char[bytes_transferred]; make a memory leak as it is never used again, boost::asio::buffer don't deallocate the memory for you.

Simply change the write handler:

void handle_write(const boost::system::error_code& error)
{
  std::cout<<"handling write and exiting."<<std::endl;
  delete this;
}
lionbest
if i do that I just get an end of file exception
Where you get the exception from? For me this code run well (boost 1.40).
lionbest
+1  A: 

You're not using boost::asio::streambuf correctly, read the HTTP client example closely. For your code, you should do something like:

buffer.commit.( bytes_transferred );
std::istream is( &buffer );
std::string data;
is >> data;
std::cout << "data: " << data << " bytes: " << bytes_transferred << std::endl;

then use a separate boost::asio::streambuf for your response. As the previous answer also said, you're leaking memory. I'd suggest using boost::shared_ptr and shared_from_this.

Sam Miller