2013-04-01 2 views
3

У меня есть код, который выполняет HTTP-запросы с использованием API WinInet асинхронно. В общем, мой код работает, но я смущен о «правильном» способе делать что-то. В документации к InternetReadFile(), говорится:Правильный способ использования InternetReadFile() асинхронно

Чтобы убедиться, что все данные извлекаются, приложение должно продолжать называть функция InternetReadFile пока функция возвращает TRUE, а параметр lpdwNumberOfBytesRead равен нулю.

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

Типичная реализация с использованием InternetReadFile() синхронно будет выглядеть примерно так:

while(InternetReadFile(Request, Buffer, BufferSize, &BytesRead) && BytesRead != 0) 
{ 
    // do something with Buffer 
} 

, но с возможностью того, что какой-либо один вызов InternetReadFile() может сигнализировать, что он собирается сделать работу асинхронно (и, возможно, прочитать часть, но не весь ваш запрос), это становится намного сложнее. Если я перейду к руководству MSDN sample code, реализация проста, просто позвонив InternetReadFile() один раз и ожидая, что один возврат будет прочитан весь запрошенный буфер либо мгновенно, либо асинхронно. Является ли это правильным способом использования этой функции или является примером кода MSDN, игнорируя возможность того, что InternetReadFile() будет читать только часть запрошенного буфера?

ответ

3

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

3

Чтение InternetReadFile() несколько раз до тех пор, пока оно не вернет TRUE и BytesRead равно 0, это правильный способ использования InternetReadFile(), но недостаточно, если вы работаете асинхронно.

Как MSDN говорит

При работе в асинхронном режиме, если вызов InternetReadFile не приводит к завершенной транзакции, он возвращает FALSE и последующий вызов GetLastError вернет ERROR_IO_PENDING. Когда транзакция будет завершена, InternetStatusCallback, указанный в предыдущем вызове InternetSetStatusCallback, будет вызываться с INTERNET_STATUS_REQUEST_COMPLETE.

Так InternetReadFile() может вернуться FALSE и установить последнюю ошибку ERROR_IO_PENDING значение, если вы работаете в асинхронном режиме.

Когда InternetSetStatusCallback снова будет вызвана с INTERNET_STATUS_REQUEST_COMPLETE, параметр lpvStatusInformation будет содержать адрес в INTERNET_ASYNC_RESULT структуры (см InternetStatusCallback callback function). INTERNET_ASYNC_RESULT.dwResult член будет содержать результат асинхронной операции (TRUE или FALSE, так как вы назвали InternetReadFile) и INTERNET_ASYNC_RESULT.dwError будет содержать код ошибки, только если dwResult является FALSE.

Если dwResult является TRUE, то ваш Buffer содержит данные, считываемые из Интернета, и BytesRead содержит число прочитанных байтов асинхронно.

Так одна из самых важных вещей, когда вы работаете асинхронном Buffer и BytesReadдолжны быть стойкими между InternetStatusCallback вызовов, т.е. не должны быть выделены в стеке. В противном случае это имеет неопределенное поведение, вызывает повреждение памяти и т. Д.