Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > [POCO] HTTPClientSession на x64


Автор: cupper 19.9.2011, 18:05
Столкнулся с таким весьма странным поведением.

В начале приложения создается сессия
Код

Poco::URI uri(properties_.host_);
        uri.setPort(properties_.port_);
        uri_ = uri;
        ptrContext_ = new Context(Context::CLIENT_USE, "", "", "", Context::VERIFY_NONE);
        session_.reset(new HTTPSClientSession(uri_.getHost(), uri_.getPort(), ptrContext_));

         if (properties_.keepAliveTimeout_)
        {
            session_->setKeepAlive(true);
            session_->setKeepAliveTimeout(Timespan(properties_.keepAliveTimeout_, 0));
        }


Далее есть процедура в которой создается хедер
Код

HTTPRequest req_post(HTTPRequest::HTTP_POST, properties_.uri_);
req_post.setVersion(HTTPRequest::HTTP_1_1);
        req_post.setContentType("text/xml");
        req_post.setContentLength(msg.size());
        req_post.set("User-Agent","bla");
        if (properties_.keepAliveTimeout_) req_post.setKeepAlive(true);
        req_post.set("Keep-Alive", "timeout=" + ((properties_.keepAliveTimeout_ > 0) ? i2str(properties_.keepAliveTimeout_) : string("5"))
            + ", max=" + i2str(properties_.keepAliveTimeout_));
        if (!cookies_.empty())
            req_post.setCookies(cookies_);

        if (!properties_.login_.empty())
        {
            HTTPBasicCredentials cred(properties_.login_, properties_.password_);
            cred.authenticate(req_post);
            assert (req_post.hasCredentials());
        }


и проиходит отправка мессаги
Код

session_->sendRequest(req_post) << msg;


Так вот. При запуске на x32 системе все работает корректно.
При запуске на x64 система наблюдается следующее поведение.

Первая мессага отправляется. Далее если отправлять мессаги следом то они отправляються так же корректно. Но если между отправкой мессаг есть интервал > 10 - 15 секунду, то строчка
Код

session_->sendRequest(req_post) << msg;


вызывает эксцепшен ConnectionAbortedException с текстом "Software caused connection abort".
Это определение эксцепшена из Poco.
Код

POCO_IMPLEMENT_EXCEPTION(ConnectionAbortedException, NetException, "Software caused connection abort")


Если же проглотить этот эксцепшен и опять сделать вызов
Код

session_->sendRequest(req_post) << msg;

то в этот раз мессага отправиться нормально.

Я в полном недоумении.

Автор: Alca 19.9.2011, 18:16
Ну так глянь сорцы

Автор: cupper 21.9.2011, 10:02
Совсем странные вещи творятся в сорцах Poco. Методом упорной правки сорцов поко, перебилда, перезапуска, локализовал место возникновения экцепшена.

в функции sendRequest(req_post)

при задержке более keepAlive происходит закрытие сокеты и его повторное открытие.
Так вот в момент закрытия сокета

Код

std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
{
    delete _pResponseStream;
    _pResponseStream = 0;

    bool keepAlive = getKeepAlive();
    if ((connected() && !keepAlive) || mustReconnect())
    {
        try
        {
        close();
        }
        catch(std::exception &ex)
        {
            std::string err = ex.what();
            err += " sendRequest()->close()";
            throw Exception(err);
        }
        _mustReconnect = false;
    }


блоки try catch добавлены уже мною в процессе локализации места возникновения ошибки. 
При вызове функции close() которая является просто врапером
Код

void HTTPSession::close()
{
    _socket.close();
}

которая опять таки тоже врапер на функцию
Код

inline void Socket::close()
{
    _pImpl->close();
}

вызывается функция
Код

void SocketImpl::close()
{
    if (_sockfd != POCO_INVALID_SOCKET)
    {
        poco_closesocket(_sockfd);
        _sockfd = POCO_INVALID_SOCKET;
    }
}

где poco_closesocket() девайн на системную функцию
Код

#define poco_closesocket(s)  closesocket(s)


так вот. если все тело функции SocketImpl::close() обернуть в блок try catch то в ней исключение не возникает. НО в функции Socket::close() которая вызывает функцию SocketImpl::close() возникает исключение которое ловиться на самом верху. 

Вопрос: как это возможно ?

Проверить в нормально дебаге нет возможность, поэтому я и вставляю везде блоки try catch, после чего пересобираю poco, после чего пересобираю свою програмулину, и переношу и запускаю на другой системе. Поэтому я допускаю возможность что я упустил чтото тривиальное, но балин, ЧТО, я по косточкам разобрал стек вызовов, нету там больше ничего, но исключение возникает, и хоть убейся я не понимаю где и почему.

Автор: cupper 21.9.2011, 12:31
и конечно же в тестовом примере это не воспроизводится. Правда тестовый пример был просто на http.
Поэтому продебажить нормально возможности нет.

Как можно узнать что и откуда бросило исключение ? И что бы в релизной сборке работало это ?

Автор: Alca 21.9.2011, 13:29
эссертами не пользуешься?

Автор: cupper 22.9.2011, 11:52
Цитата(Alca @ 21.9.2011,  13:29)
эссертами не пользуешься?

пользуюсь. Правда не понял к чему вы.

Переустановил систему на x64, пересобираю либы, буду пробовать снова. 

Автор: Alca 22.9.2011, 11:54
Цитата

Правда не понял к чему вы.

К тому, что надо проверять, анализировать то, что вернула какая-либо функция

Автор: cupper 27.9.2011, 21:51
Цитата(Alca @ 22.9.2011,  11:54)
Цитата

Правда не понял к чему вы.

К тому, что надо проверять, анализировать то, что вернула какая-либо функция

либа возвращала эксцепшен из пустого места, я хз что тут модно асертом проверить. Я все что можно позатыкал try catch блоками, но оно мезду ними умудрялось возникать. В итогде была була установленна x64 система, пересобраны либы, и... эксцепшен перестал возникать. 

Автор: Alca 27.9.2011, 22:02
Цитата

из пустого места

веришь в чудеса?

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