Question

I'm looking for the best way to modify the Boost Asio HTTP Server 3 example to maintain a list of the currently connected clients.

If I modify server.hpp from the example as:

class server : private boost::noncopyable
{
public:
    typedef std::vector< connection_ptr > ConnectionList;

    // ...

    ConnectionList::const_iterator GetClientList() const
    {
        return connection_list_.begin();
    };

    void handle_accept(const boost::system::error_code& e)
    {
        if (!e)
        {
            connection_list_.push_back( new_connection_ );
            new_connection_->start();
            // ...
        }
    }

private:
    ConnectionList connection_list_;
};

Then I mess up the lifetime of the connection object such that it doesn't go out of scope and disconnect from the client because it still has a reference maintained in the ConnectionList.

If instead my ConnectionList is defined as typedef std::vector< boost::weak_ptr< connection > > ConnectionList; then I run the risk of the client disconnecting and nullifying its pointer while somebody is using it from GetClientList().

Anybody have a suggestion on a good & safe way to do this?

Thanks, PaulH

Was it helpful?

Solution

HTTP is stateless. That means it's difficult to even define what "currently connected client" means, not to mention keeping track of which clients are at any given time. The only time there's really a "current client" is from the time a request is received to the time that request is serviced (often only a few milliseconds). A connection is not maintained even for the duration of downloading one page -- rather, each item on the page is requested and sent separately.

The typical method for handling this is to use a fairly simple timeout -- a client is considered "connected" for some arbitrary length of time (a few minutes) after they send in a request. A cookie of some sort is used to identify the client sending in a particular request.

The rest of what you're talking about is just a matter of making sure the collection you use to hold connection information is thread safe. You have one thread that adds connections, one thread that deletes them, and N threads that use the data currently in the list. The standard collections don't guarantee any thread safety, but there are others around that do.

OTHER TIPS

Sorry, I do not have enough Reputation to comment, so I'll write it here.

Comment on answer: "HTTP is stateless" - but the connection is statefull! Please carefully read HTTP/1.1 docs, the default behavior is "Connection: keep-alive", so if you implement HTTP server you must wait for another request on the same connection. This is especially important for HTTPS, saves lots of time by reducing number of handshakes. That's why every conforming server must understand how to keep connections.

Regarding the question, there is some logic in you "connection" class - in every handler of async operation, you either start another async operation or stop the whole chain (error, everything done, etc.)

Write a function in your "connection" class, like tell_server_im_done, in that function tell your "server" instance to remove yourself from the list. You should give you "connection" constructor a pointer or reference to your server object for this to work.

Advice on multithreading: start by doing everything in the single thread. You need good understanding of threading to do the whole thing right with several threads, so if your server is not overloaded, keep it single-threaded as long as possible. :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top