0

Hey guys, i'm a newbie to async-programming, this is probably a stupid question, but it indeed drove me crazy!!

Here's the code (it just modified a bit from boost.asio's sample):

server.cpp:

class tcp_server
{
public:
    tcp_server(boost::asio::io_service& io_service)
        : acceptor_(io_service, tcp::endpoint(tcp::v4(), 10000)),limit(0)
    {
        start_accept();
    }

private:
    void start_accept()
    {
        while(1)
        {
            if(limit <= 10)
            {
                std::cout << limit << std::endl;
                break;
            }
        }

        tcp::socket* socket = new tcp::socket(acceptor_.io_service());

        acceptor_.async_accept(*socket,
            boost::bind(&tcp_server::handle_accept, this, boost::asio::placeholders::error));
    }

    void handle_accept(const boost::system::error_code& error)
    {
        if (!error)
        {
            ++limit ;
            start_accept();
        }
    }

    tcp::acceptor acceptor_;

    int limit;
};

int main()
{
    try
    {
        boost::asio::io_service io_service;
        tcp_server server(io_service);
        io_service.run();
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}

client.cpp:

int main(int argc, char* argv[])
{
    int i = 0;

    while(1)
    {
        try
        {
            boost::asio::io_service io_service;

            tcp::resolver resolver(io_service);
            tcp::resolver::query query("127.0.0.1", "10000");
            tcp::resolver::iterator endpoint_iterator =resolver.resolve(query);
            tcp::endpoint endpoint = *endpoint_iterator;

            tcp::socket socket(io_service);
            socket.close();
            socket.connect(endpoint);

            std::cout << i++ << std::endl;
        }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
        }
    }

    return 0;
}

I just wanna limit server to accept 10 client. However, client cout the error information after it cout "amazing" 210 (never more or less) continuous numbers. What happend??

rhapsodyn
  • 3,272
  • 5
  • 29
  • 36

1 Answers1

3

I've changed server.cpp a bit. First reconfigured acceptor_ on constructor. Removed while loop, added acceptor_.close();

#include <boost/asio/io_service.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>

using namespace boost::asio;
using namespace boost::asio::ip;

class tcp_server
{
public:
    tcp_server(boost::asio::io_service& io_service)
        : acceptor_(io_service),limit(0)
    {
        tcp::endpoint endpoint(tcp::v4(), 10000);
        acceptor_.open(endpoint.protocol());
        acceptor_.bind(endpoint);
        acceptor_.listen(1); //accept 1 connection at a time
        start_accept();
    }

private:
    void start_accept()
    {
        tcp::socket* socket = new tcp::socket(acceptor_.io_service());
        acceptor_.async_accept(*socket,
            boost::bind(
                &tcp_server::handle_accept,
                this,
                socket,
                boost::asio::placeholders::error));
    }

    void handle_accept(tcp::socket* s, const boost::system::error_code& error)
    {
        if (!error)
        {
            ++limit;
            if (limit < 9)
            {
                start_accept();
            }
            else
            {
                acceptor_.close();
            }           

        }
    }

    tcp::acceptor acceptor_;

    int limit;
};

int main()
{
    try
    {
        boost::asio::io_service io_service;
        tcp_server server(io_service);
        io_service.run();
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}

I suppose, default acceptor can async_accept 200 connection events at a time. You open a socket and close it from the client side in an infinite loop. As a result you open and close a connection 200 times, but it is still 1 connection, 1 socket.

Capping it to 1 by calling listen(1), would force the acceptor to fire an event. You increase the count, then client closes the connection. This way you correctly count each connection event.

Last note: async io uses 1 thread to process connection events, retrieved data etc... Thus, use of mutexes are not necessary.

vahapt
  • 1,685
  • 1
  • 21
  • 26
  • +1 splitting up the `acceptor` ctor into `open` `bind` `listen` is the correct approach here. – Sam Miller Mar 10 '11 at 17:23
  • +1: I've deleted my answer as I completely misunderstood the problem. – Troubadour Mar 10 '11 at 20:06
  • errrrrr.. one more question: if client doesn't close the socket (but they may be closed later), how can the server get & limit the **actual** connection count? – rhapsodyn Mar 13 '11 at 09:06
  • I'd keep a list of unique socket pointers. I'm not an expert on async sockets but if you were using sync sockets then read-write functions would wait until a data is received-written or throw an exception if the connection is down. I'm pretty sure boost can fire an async event when the connection is down. Additionally you might check continuously if the socket is still connected. (Though i do not recommend polling since it consumes CPU and you should have enabled keep-alive parameter) See also http://stackoverflow.com/questions/1511129/boostasioiptcpsocket-is-connected – vahapt Mar 13 '11 at 11:58