Есть программа, использует WinInet, нормально общается с сервером в интернете по HTTPS.
Чтобы иметь больший контроль над сокетами хочется отказаться от WinInet, создавать и настраивать сокеты вручную, поддержку HTTPS реализовать, например, с помощью OpenSSL.
Тут обнаруживается проблема: через примерно 40-50 секунд после установления соединения вызов SSL_read возвращает 0,
при этом
Судя по обсуждениям в интеренете причиной может быть закрытие соединения сервером.
Пока не догадываюсь, как искать причину такого поведения сервера.
Напоминаю, что WinInet-версия приложения работает без таких проблем, так что ошибка скорее всего наведена клиентским приложением.
В HTTP-запросах "Connection: Keep-Alive" указываю (хоть для HTTP 1.1 это не принципиально).
Приложение отправляет запрос на сервер и получает ответ не реже 1 раза в секунду.
Вообще, формы НТТР-запросов подсмотрел фидлером у WinInet-версии программы и использую их в OpenSSL-версии.
Только cookie из запросов выбросил, но уверен на 99,9% что дело не в них.
Возможно дело в неправильном использовании OpenSSL?
Работаю с ним впервые.
Какие могут быть идеи, в чем может быть проблема или как её искать?
SOCKET socket[ 2 ];
SSL* sslHandle[ 2 ];
for ( int i = 0; i < 2; ++i ) {
socket[ i ] = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0 );
connect( socket[ i ], &saddr, sizeof( saddr ) );
sslHandle[ i ] = SSL_new( sslContext );
SSL_set_fd( sslHandle[ i ], socket[ i ] );
SSL_connect( sslHandle[ i ] );
}
Эти 2 соединения будут использоваться паралельно и независимо друг от друга.
Например, как если бы они были установлены разными браузерами или даже установлены с разных компьютеров.
После чего основной поток использует первое соединение
Оба потока успешно выполняют положенную работу:
SSL_write возвращает управление мгновенно (видимо, копирует данные в локальные буферы),
SSL_read (вызванный сразу после выхода из SSL_write) возвращает управление через несколько сотен миллисекунд, когда приходит ответ из сети.
Через 40-50 секунд всё ломается.
SSL_write возвращает правильное число записанных байт.
После чего SSL_read немедленно возвращает 0.
SSL_get_error() возвращает SSL_ERROR_SYSCALL.
Использую
VC++ 2010
Win32 OpenSSL v1.0.1e
Приложение линкуется статически с библиотеками
...\OpenSSL-Win32\lib\VC\static\libeay32MT.lib
...\OpenSSL-Win32\lib\VC\static\ssleay32MT.lib
Как думаете, в чем может быть проблема или как искать причину сбоя?
Здравствуйте, i3F, Вы писали:
i3F>Судя по обсуждениям в интеренете причиной может быть закрытие соединения сервером. i3F>Пока не догадываюсь, как искать причину такого поведения сервера. i3F>Напоминаю, что WinInet-версия приложения работает без таких проблем, так что ошибка скорее всего наведена клиентским приложением.
WinInet может молча пересоздавать соединение, он такой.
Посмотри тем же фидлером, что там с соединением происходит.
Здравствуйте, Mиxa, Вы писали:
M>WinInet может молча пересоздавать соединение, он такой. M>Посмотри тем же фидлером, что там с соединением происходит.
Вы правы, подержал фидлер несколько минут, видны периодические (как раз через ~40 секунд) реконнекты.
Спасибо!
Теперь надо понять, почему эти реконнекты происходят.
Попробую с техподдержкой сервера пообщаться.
O>1. Не знаток OpenSSL, но в приведенном коде смущает то, что один объект SSL_CTX O>используется для двух сокетов.
Так и должно быть, CTX (context) — это, по сути, объект, который держит сертификаты, настройки шифров и т.п.. Потом из одного контекста нужно спавнить сколько угодно соединений с одинаковыми сертификатами.
Здравствуйте, Mиxa, Вы писали:
M>Здравствуйте, i3F, Вы писали:
i3F>>Теперь надо понять, почему эти реконнекты происходят. i3F>>Попробую с техподдержкой сервера пообщаться.
M>А зачем вообще низкий уровень потребовался? Если WinInet не устраивает, то есть еще WinHTTP. Да и cURL в конце-концов.
Нужно указать используемый локальный сетевой интерфейс.
bind() требует знания сокета.
Нужно отключить алоритм Нагла.
Вроде как WinInet в моем случае нагла выключает (хук на setsocketopt это показывает), но нет уверенности, что WinInet всегда так делает.
Здравствуйте, i3F, Вы писали:
M>>А зачем вообще низкий уровень потребовался? Если WinInet не устраивает, то есть еще WinHTTP. Да и cURL в конце-концов.
i3F>Нужно указать используемый локальный сетевой интерфейс. i3F>Нужно отключить алоритм Нагла.
cURL это все позволяет делать. CURLOPT_INTERFACE и CURLOPT_TCP_NODELAY.
Здравствуйте, i3F, Вы писали: i3F>Как думаете, в чем может быть проблема или как искать причину сбоя?
Прежде чем общаться с техподдержкой сервера проверьте правильно ли у вас всё с I/O:
1) Сокеты блокируемые?
2) SSL_ERROR_WANT_READ,SSL_ERROR_WANT_READ обрабатываете?
В общем если подробнее код вашего I/O покажете, тогда можно о чем-то говорить.
Хотя если отключате Nagle, то могут и отсюда какие-то проблемы. Вроде как отключение Nagle может быть опциональным как с стороны клиента так и сервера. Так вот если в вашем случае отключение идёт только с клиентской стороны могут быть и в связи с этим какие-то проблемы.