Откуда происходит таинственное соединение 200? - PullRequest
0 голосов
/ 10 марта 2011

Эй, ребята, я новичок в асинхронном программировании, это, наверное, глупый вопрос, но это действительно сводило меня с ума !!

Вот код (он только немного изменился из примера boost.asio):

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

Я просто хочу ограничить сервер, чтобы принять 10 клиентов. Однако клиент получает информацию об ошибке после того, как он «удивительно» 210 (никогда более или менее) непрерывных чисел. Что случилось ??

1 Ответ

3 голосов
/ 10 марта 2011

Я немного изменил server.cpp. Сначала перенастроить acceptor_ на конструкторе. Удален цикл while, добавлен 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;
}

Полагаю, акцептор по умолчанию может async_accept 200 событий подключения одновременно. Вы открываете сокет и закрываете его со стороны клиента в бесконечном цикле. В результате вы открываете и закрываете соединение 200 раз, но это все еще 1 соединение, 1 сокет.

Ограничение до 1 вызовом listen (1) заставит акцептор запустить событие. Вы увеличиваете количество, а затем клиент закрывает соединение. Таким образом, вы правильно подсчитываете каждое событие подключения.

Последнее примечание: async io использует 1 поток для обработки событий подключения, извлеченных данных и т. Д. Таким образом, использование мьютексов необязательно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...