Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > boost::asio & async_connect


Автор: Kirgston 4.9.2011, 20:24
Всем доброго времени суток! Дело такое... есть класс(клиент) который должен асинхронно работать с сервером. Проблема очень странного характера. 

Есть:

Код

    void Connect(char* ip, int port, int Type)
    {
        this->Type = Type;

        socket_.async_connect(this->endpoint,
            boost::bind(&wsJoinServerCli::handle_connect, 
            this,
            boost::asio::placeholders::error));

        SendBytes = 0;
    }


    void handle_connect(const boost::system::error_code& error) 
    {
        if (!error)
        {
            this->socket_.async_receive(boost::asio::buffer(data_, max_length),
            boost::bind(&wsJoinServerCli::handle_read, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));

            Connected = true;
        }
        else
        {
    
        }
    }


Всё это члены класса wsJoinServerCli. Забавно то что оно работает так сказать через раз. Точнее через неделю. Одну неделю я компилирую код и всё хорошо. На сл. неделю (это всё конечно утрировано и примерно) тот же код без йоты изменений уже не работает. Как только я делаю:

Код

    void Connect(char* ip, int port, int Type)
    {
        this->Type = Type;
        this->endpoint = tcp::endpoint(boost::asio::ip::address::from_string(ip), port);
        socket_.connect(this->endpoint, port);
        Connected = true;
        SendBytes = 0;
    }


Сразу всё начинает работать. А в первом варианте handle_connect попросту не вызывается. Никаких ошибок, никаких проблем. Она просто не вызывается. Вот и сижу уже битые часа 4 и понять не могу. Облазил примеры с буста там примерно всё так же. В чем ошибка понять не могу. А ведь хочется чтобы работал полностью асинхронно =) а не то что в одном месте мы синхронные в другом асинхронны.  smile 

Так же еще один вопрос из разряда "глупости". Интересует как правильно(!) отправлять данные в асинхронном р-ме. А точнее: есть например структура, тут понятно, её просто пакуем в shared_pointer и кидаем в async_send(). А что если не структура? А просто массив еще и неизвестной длинны? Сколотить из него структуру я явно не могу. Длинна узнается прямо перед отправкой. Как тут быть? 

Автор: mabrarov 4.9.2011, 22:11
Непонятно, как (кто, когда, чем) в первом варианте заполняется this->endpoint? Действительно ли там всегда содержится что-то вменяемое на момент вызова async_connect? Все это сильно зависит от остального кода.

Автор: Kirgston 4.9.2011, 22:30
Цитата(mabrarov @  4.9.2011,  22:11 Найти цитируемый пост)
в первом варианте заполняется this->endpoint?

Так же как и во втором варианте =) просто у меня код один, вот и чтобы не выкладывать код с закоментироваными строчками я его чистил. Вот и случайно удалил эндпоинт. В реальном случае он вменяемо заполняется. Абсолютно теми же данными. Причем в первом случае не просто каллбэка нету а и вообще коннекта. 

Автор: boostcoder 4.9.2011, 22:34
Цитата(Kirgston @  4.9.2011,  22:30 Найти цитируемый пост)
Причем в первом случае не просто каллбэка нету а и вообще коннекта.

т.е. ты хочешь сказать, что мало того что коннекта не происходит, так еще и хендлер не вызывается? а если вызывается, то error_code чему равен?

Цитата(Kirgston @  4.9.2011,  20:24 Найти цитируемый пост)
есть например структура, тут понятно, её просто пакуем в shared_pointer и кидаем в async_send().

без сериализации?

Цитата(Kirgston @  4.9.2011,  20:24 Найти цитируемый пост)
А что если не структура? А просто массив еще и неизвестной длинны? Сколотить из него структуру я явно не могу. Длинна узнается прямо перед отправкой. Как тут быть?

поясните...

Автор: Kirgston 4.9.2011, 22:43
Цитата(boostcoder @  4.9.2011,  22:34 Найти цитируемый пост)
т.е. ты хочешь сказать, что мало того что коннекта не происходит, так еще и хендлер не вызывается?

да, именно. Как будто вникуда идет socket_.async_connect(). Само собой кода ошибки не имею


Цитата(boostcoder @  4.9.2011,  22:34 Найти цитируемый пост)
без сериализации?

Угу. Через shared_pointer. Например вот так вот:


Код

    boost::shared_ptr<STRUCT> pResult(new STRUCT);
    AsyncWrite(pResult, pResult->h.size);

    ....

    template<typename T> void AsyncWrite(boost::shared_ptr<T> data, int len)
    {
        socket_.async_send(boost::asio::buffer(data.get(), len),
            boost::bind(&DataSession::handle_write, shared_from_this(),
            boost::asio::placeholders::error));
    }


Не помню кто и где , но мне подсказали что так будет нормально. И указатель со структурой сами удалятся после использования


Цитата(boostcoder @  4.9.2011,  22:34 Найти цитируемый пост)
поясните... 

Буст асио он ведь не риал тайм(если не ошибаюсь). И если я создаю локальный(!) буфер в котором формирую список данных и передаю этот буфер в async_send(). Отправка данных понятное дело не моментальная, может отправится через 0.1с а может и через 1с. Но после выхода из блока этот статический буфер само собой уничтожится. В итоге асио попытается отправить те данные которых уже нету, либо на ихнем адресе лежат уже другие данные

Автор: boostcoder 4.9.2011, 23:07
Цитата(Kirgston @  4.9.2011,  22:43 Найти цитируемый пост)
Как будто вникуда идет socket_.async_connect().

компилятор/ОС/версия_boost ?

Автор: mabrarov 4.9.2011, 23:23
Цитата(Kirgston @ 4.9.2011,  22:30)
Причем в первом случае не просто каллбэка нету а и вообще коннекта.

Надо проверить:
  • не закрывается (уничтожается) ли сокет сразу после вызова async_connect
  • как идет работа с соотв. asio::io_service

Автор: Kirgston 4.9.2011, 23:40
Цитата(boostcoder @  4.9.2011,  23:07 Найти цитируемый пост)
компилятор/ОС/версия_boost ?

MSVC 2010 Sp1
boost 1.47
XP Sp3


Автор: Kirgston 5.9.2011, 08:45
user posted image

Забавно вот что... может я и не на то смотрю. Но тем не менее. Когда делаю:
Код

this->endpoint = tcp::endpoint(boost::asio::ip::address::from_string(ip), port);

Эндпоинт отлично заполняется. Но обратите внимание на то как он заполняется когда я вызываю connect(). Эндпоинт попросту не заполнен

user posted image

Так же чуток забавно с async_connect. State у них разные. Я уже даже не понимаю куда копать :(




Автор: boostcoder 5.9.2011, 14:22
такое предположение: если при использовании connect(), у тебя все работает, потому что каждый раз при его вызове ты заново инициализируешь endpoint, значит, в противном случае, значение endpoint`а который ты используешь для async_connect() чем-то затирается.

попробуй перед каждым async_connect() инициализировать endpoint.

Автор: Kirgston 5.9.2011, 14:26
Цитата(boostcoder @  5.9.2011,  14:22 Найти цитируемый пост)
попробуй перед каждым async_connect() инициализировать endpoint. 

Так вот же на втором скрине видно что он инициализируется перед async_connect(). 

Что 


Код

socket_.async_connect(this->endpoint,
            boost::bind(&wsJoinServerCli::handle_connect, 
            this,
            boost::asio::placeholders::error));


Что


Код

socket_.async_connect(tcp::endpoint(boost::asio::ip::address::from_string(ip), port),
            boost::bind(&wsJoinServerCli::handle_connect, 
            this,
            boost::asio::placeholders::error));


Разницы нету

Автор: boostcoder 5.9.2011, 14:38
показывай больше кода. а лучше компилябельный код воспроизводящий проблему.

Добавлено через 48 секунд
может то, куда ты коннектишься, тупо висит?

Автор: mabrarov 5.9.2011, 14:45
Еще раз повторю:
  • раз есть проблемы с самим connect, то, скорее всего, socket разрушается (закрывается) до окончания асинхронной операции;
  • раз есть проблемы с вызовом handler, то это значит, что соотв. io_service уже "не крутится".
Мужики, ну сколько таких проблем описано в asio-users mailing list? И все снова туда же. Весь код в студию! Хотя бы минимальный работающий пример, демонстрирующий проблему.

Автор: boostcoder 5.9.2011, 15:03
Цитата(mabrarov @  5.9.2011,  14:45 Найти цитируемый пост)
раз есть проблемы с самим connect, то, скорее всего, socket разрушается (закрывается) до окончания асинхронной операции;

я подумал что ТС в курсе что сервер не должен обрывать соединение ;)

Автор: mabrarov 5.9.2011, 15:21
Цитата(boostcoder @ 5.9.2011,  15:03)
Цитата(mabrarov @  5.9.2011,  14:45 Найти цитируемый пост)
раз есть проблемы с самим connect, то, скорее всего, socket разрушается (закрывается) до окончания асинхронной операции;

я подумал что ТС в курсе что сервер не должен обрывать соединение ;)

Все в курсе. Все (полностью) читали документацию. И все начинают оптимизировать (или просто боятся мифических циклических ссылок) и выкидывают enable_shared_from_this. Наболело. Если не лень - подсчитайте, сколько было аналогичных вопросов в списке рассылки по Asio.

Да, можно обойтись без enable_shared_from_this. Но надо читать доки, где четко описаны требования к времени жизни всех компонент, входящих в асинхронную операцию.

Надеюсь, я не прав и тут действительно баг в Asio. Без обид. Действительно буду рад найти и излечить баг (в Asio) раньше, чем он испортит жизнь лично мне.

Автор: boostcoder 5.9.2011, 15:33
Цитата(mabrarov @  5.9.2011,  15:21 Найти цитируемый пост)
выкидывают enable_shared_from_this

это страшно..

Автор: mabrarov 5.9.2011, 17:21
Цитата(boostcoder @ 5.9.2011,  15:33)
Цитата(mabrarov @  5.9.2011,  15:21 Найти цитируемый пост)
выкидывают enable_shared_from_this

это страшно..

Типичный пример premature optimization. Реально Яндекс вот юзает io_service-per-thread (дабы данные "парковались" в пределах кэша соотв. ядра CPU) - не удивлюсь, если они не юзают shared_from_this дабы избежать лишних барьеров памяти. На BoostCon 2011 Chris рассказывал, что можно и без enable_shared_from_this - вот только никто разницу никогда не считал и не приводил диаграмм, а вот "общий уровень опасности" это здорово увеличивает.

Автор: boostcoder 5.9.2011, 17:41
Цитата(mabrarov @  5.9.2011,  17:21 Найти цитируемый пост)
io_service-per-thread

я в каком-то OpenSource проекте такое видал. удивился...

Автор: Kirgston 5.9.2011, 18:12
В последсвии очень странных ошибок(МССКЛ начал отваливатся на валидных кусках кода, когда я заходил через менеджер и подключался там, а после просто закрывал ничего при этом не делая - всё сразу становилось норм) которых я за 2 дня нахапал столько сколько не ловил целое лето... решил попросту формат Ц, и поставить винду 7 (сейчас ХР). Думаю уже к вечеру попробую всё перекомпилить. Может поможет  smile . Т.к. подмечу что раньше этот участок кода (без йоты изменений) работал корректно (даже при бусте 1.47)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)