Будут ли успешно выполняться асинхронные вызовы через wininet, если мы ожидаем ответа в бесконечном цикле while? - PullRequest
0 голосов
/ 30 апреля 2019

У меня есть приложение, которое использует Wininet в главном потоке для синхронизации и асинхронных вызовов.Единственный корневой интернет-дескриптор открывается с флагом - INTERNET_FLAG_ASYNC.Этот дескриптор используется для всех вызовов. Чтобы реализовать синхронизированные сетевые вызовы, мы просто ждем бесконечный цикл while, пока запрос не завершится.Периодически мы видим, что мы не получаем никакого ответа от Wininet.

Некоторые фрагменты кода / псевдокод ниже, которые показывают, что мы пытаемся сделать.


// struct Context{
    bool resultReady;
}

// Callback function registered with Wininet to know about the progress of ongoing call 
static void CALLBACK StatusCallBack (
                     IN HINTERNET           hInternet,
                     IN DWORD_PTR           dwContext,
                     IN DWORD               dwInternetStatus,
                     IN LPVOID              lpvStatusInformation OPTIONAL,
                     IN DWORD               dwStatusInformationLength ) 
{
    Context* cxt = (Context *)dwContext;
    switch (dwInternetStatus) { 
        // other cases ... 
        case INTERNET_STATUS_REQUEST_COMPLETE : 
            cxt->resultReady = true; break;
    }
}


// Open root internet handle
HINTERNET root_hnd = InternetOpenA(agentname, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC);

// Set status callback 
InternetSetStatusCallback(root_hnd, StatusCallBack );

// Open connect handle 
Context connect_cxt = {};
HINTERNET connect_hnd = InternetConnectA(root_hnd, hostname, NULL, NULL, INTERNET_SERVICE_HTTP, 0, &connect_cxt);

// Open HTTP request handle 
Context http_cxt= {};
DWORD flags = INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RELOAD | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS;
HINTERNET http_hnd = HttpOpenRequestA(connect_hnd, verb, objectname, HTTP_VERSIONA, NULL, NULL, flags, &http_cxt);

HttpSendRequestA(file, NULL, 0, additionalOptions, optionsLen);

while(http_cxt.resultReady == false) {
    Sleep(10);
}

Это всего лишь фрагмент того, что мы делаем.У нас есть обработка ошибок на каждом этапе и механизм синхронизации также на месте.Для звонков на одно и то же имя хоста мы также повторно используем дескриптор интернет-соединения, но каждый раз открываем новый дескриптор http-запроса.

После отладки мы обнаружили, что если на одном и том же сервере выполняется несколько асинхронных вызовов, Wininet помещает их в очередь и фактически не отправляет запрос, если не завершены предыдущие: http://webdebug.net/2013/01/wininet-connection-limit/

Мы исправили эту проблему, увеличив допустимый лимит соединения и вызывая сбои при самом инициировании, если лимит все еще превышен.Тем не менее, мы все еще наблюдаем те же симптомы иногда даже в тех случаях, когда серверу выполняется только один асинхронный вызов (параллельно могут выполняться другие вызовы с другими серверами).После того как мы сделаем запрос на отправку, мы не получим никакого ответа в нашей зарегистрированной функции обратного вызова.

Я хочу знать, нужен ли Wininet поток, для которого открываются дескрипторы, чтобы освободить его, чтобы он отправлял нам какие-то текущие обратные вызовы?Кроме того, есть ли какой-либо другой предел соединения, который мы могли бы пропустить?

...