Ошибка потоковой передачи: InternetSetStatusCallback вызывается снова до выхода из предыдущего вызова - PullRequest
0 голосов
/ 15 февраля 2019

Я использую InternetSetStatusCallback для потоковой передачи данных:

CallbackPointer = InternetSetStatusCallback(SessionHandle,
    (INTERNET_STATUS_CALLBACK)CallBack);

Иногда нижеуказанная функция CallBack вызывается снова перед выходом, несмотря на то, что потоковые данные отправляются каждые 250 мс, поэтому у программы должно быть достаточно времени дляобработать данные.

bool InsideFunc = false;

VOID CALLBACK
CallBack(
__in HINTERNET hInternet,
__in DWORD_PTR dwContext,
__in DWORD dwInternetStatus,
__in_bcount(dwStatusInformationLength) LPVOID lpvStatusInformation,
__in DWORD dwStatusInformationLength
)
{
    if (InsideFunc)
    {
            // should not happen
    }
    InsideFunc = true;

    cOandaFeed* oandaFeed = (cOandaFeed*)dwContext;
    ASSERTRETURN(oandaFeed);

    ASSERT(dwContext);

    switch (dwInternetStatus) {
    case INTERNET_STATUS_HANDLE_CREATED:
        oandaFeed->StatusHandle = lpvStatusInformation;
        break;
    case INTERNET_STATUS_REQUEST_COMPLETE:
        if (oandaFeed->State == cOandaFeed::OPENING)
            oandaFeed->StartFeeding();
        break;
    case INTERNET_STATUS_RESPONSE_RECEIVED:
        if (oandaFeed->State == cOandaFeed::FEEDING) {
            oandaFeed->ReadFile(); // this is where I call InternetReadFileEx
            oandaFeed->CollectAndForwardChunks();
        }
        break;
    case INTERNET_STATUS_HANDLE_CLOSING:
        oandaFeed->SetState(cOandaFeed::IDLE);
        break;
    case INTERNET_STATUS_RECEIVING_RESPONSE:
        break;
    }

    InsideFunc = false;
}

Таким образом, программа правильно инициализирует, а затем получает ответы статуса INTERNET_STATUS_RECEIVING_RESPONSE и INTERNET_STATUS_RESPONSE_RECEIVED среди других.Все идет нормально.Но следующая итерация идет не так, InternetReadFileEx вызывается дважды и получает сообщения об ошибках, одно для ожидающего ввода-вывода и одно для внутренней ошибки InternetReadFileEx.Следующий раунд снова хорош, а потом ошибки.

Я сделал трюк «bool insideFunc», чтобы увидеть, происходит ли то, что я подозреваю, и да, иногда «вызов» является правдой перед установкой, поэтому иногда это так.называется до того, как это закончится.Я только хочу прочитать мое сообщение на INTERNET_STATUS_RESPONSE_RECEIVED, но иногда CallBack () вызывается снова до его завершения, и InternetReadFileEx происходит с неправильной синхронизацией, в результате чего он возвращает коды ошибок 997 и 12004.

Как это исправить?

1 Ответ

0 голосов
/ 16 марта 2019

Мне удалось это легко исправить.Проблема заключалась в том, что я сохранил свой вызов ReadFile () в случае INTERNET_STATUS_RESPONSE_RECEIVED в коммутаторе.Это вызвало проблемы, потому что это состояние отправляется через обратный вызов , когда он находится внутри вызова InternetReadFileEx () , внутри моего ReadFile (), вызывая рекурсивный вызов ReadFile () снова.

Таким образом, первый вызов ReadFile () привел к 997: ERROR_IO_PENDING, а второй вызов (вызванный, но рекурсия) привел к внутренней ошибке 12004:

Решение: После того, как я переехалмой ReadFile () для случая INTERNET_STATUS_REQUEST_COMPLETE в коммутаторе, я получаю только ERROR_IO_PENDING, так как мы не получаем CallBack внутри ReadFile (), с этим статусом.Мы получаем это состояние асинхронно, задолго до того, как InternetReadFileEx () вернулся.ERROR_IO_PENDING является нормальным:

Примечание. Код GetLastError ERROR_IO_PENDING не является ошибкой;он обозначает, что операция чтения ожидает завершения в асинхронном режиме.

в кавычках от https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-readfile

Потоковые работы

  1. Вызов InternetReadFileEx ()
  2. возвращает ожидающий ввод-вывод
  3. , когда у него есть новые данные (цена), он просто отправляет его асинхронно через INTERNET_STATUS_REQUEST_COMPLETE.
  4. Если у него нет данных (без изменения цены)в течение нескольких секунд он просто посылает сердцебиение через INTERNET_STATUS_REQUEST_COMPLETE, чтобы избежать тайм-аута.
  5. Я немедленно снова вызываю InternetReadFileEx (), после того как я получил данные (см. # 1)

ЭтоКак работает потоковое вещание в Oanda, но я думаю, что это обычная практика?

Спасибо всем за ответы.

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