我有异步使用WinInet API执行HTTP请求的代码。一般来说,我的代码有效,但我对“正确”的做事方式感到困惑。在InternetReadFile()的文档中,它声明:
为确保检索所有数据,应用程序必须继续调用 InternetReadFile函数,直到函数返回TRUE和 lpdwNumberOfBytesRead参数等于零。
但在异步模式下,它可能(或可能不)返回false,并且错误为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()
只读取部分请求缓冲区的可能性?
答案 0 :(得分:3)
在仔细阅读异步示例之后,我现在看到它重复读取,直到遇到成功读取0字节为止。所以要回答我自己的问题,你必须一遍又一遍地调用InternetReadFile(),并为同步或异步响应做好准备。
答案 1 :(得分:3)
重复读取InternetReadFile()
直到它返回TRUE而BytesRead为0是使用InternetReadFile()
的正确方法,但如果你异步工作则不够。
正如MSDN所说
异步运行时,如果对InternetReadFile的调用未导致已完成的事务,则它将返回FALSE,随后对GetLastError的调用将返回ERROR_IO_PENDING。事务完成后,将使用INTERNET_STATUS_REQUEST_COMPLETE调用先前对InternetSetStatusCallback的调用中指定的InternetStatusCallback。
如果您在异步模式下工作,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
仅包含错误代码{ {1}}是dwResult
。
如果FALSE
为dwResult
,则TRUE
包含从Internet读取的数据,Buffer
包含异步读取的字节数。
因此,当您异步工作时,最重要的事情之一是BytesRead
和Buffer
必须在BytesRead
次来电之间保持不变,即一定不能在堆栈上分配。否则它有未定义的行为,导致内存损坏等。