user1759872
user1759872

Reputation: 51

Boost asio tcp, why cant I have only one data socket on the server side that can be opened and closed

In brief my question is if you have a tcp server that will only ever have one active connection can you just create one server side data socket. In all the tutorials, I see that a new socket is created and I don't understand why this has to be the case. Why not create one server side socket and then open, close, reset it (which I originally hoped async_accept somehow did)?

In more detail:

I've gone through the boost asio tutorial for an asynchronous day time server and can get it to compile and work. I can even modify it for my application and get it to run as I desire :) . However, my original approach didn't work and I don't understand why which is where I was hoping for your help.

Basically I wanted to create a TCP server that would only accept one TCP client and ignore all others unless that first client disconnected. I did this using acceptor.close() and acceptor.open() so that when the first connection was accepted I just closed the acceptor, then whenever I picked up an eof error I reopened the acceptor to listen for new connections. I naively thought that because I only ever wanted one active connection I only needed to create a single:

boost::asio::ip::tcp::socket socket_

As I only ever have one data socket receiving data from a client it seems overkill to create a whole tcp_connection class, as per the tutorial, that as far as I could tell only returned a new socket constructed with the io_service. (In the tutorial I think every time the server accepts a new connection a new socket is created using this code):

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


 private:
  tcp_connection(boost::asio::io_service& io_service)
    : socket_(io_service)
  {
  }

  tcp::socket socket_;
  std::string message_;
};

I therefore tried to use just one boost::asio::ip::tcp::socket. I initialised this in the constructor of my server class using the io_service in a similar way to the tutorial above. My testing showed that my first client would connect and only after the first had disconnected would the second connect. However, regardless of what I did the data buffer on the async_accept(socket_,.....) call would never get filled. Initially I just kept getting eof errors, then I tried closing the socked and reopening which removed the eof error and gave a transport end not connected error. Obviously I'm doing something very stupid here but I can't see what is wrong philosophically speaking with what I'm trying to do. When I create a new socket using the tutorial technique everything works as expected.

So my question is can I just have a single socket and do something like cancel, close, open? Am I meant to bind or something else but isn't that async_accept job?

I've only used boost asio for a week now and this is my first ever post to a forum like this so go easy on me ;) .

Upvotes: 5

Views: 1907

Answers (1)

Brian White
Brian White

Reputation: 8756

You could, but you can't.

There is no reason why TCP could not be implemented as you state but no operating system I'm aware of does so.

The reason is quite simple in that the OS must support multiple concurrent connections and so that is the design requirement that dictates the implementation. To achieve the "there can only be one" case, simply close the listener socket after successfully accepting the new connection and re-open it later. It's not usually worth the effort to do so.

The overhead you describe is minimal and not worth trying to optimizing out.

Upvotes: 3

Related Questions