3

我有使用 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 示例代码寻求指导,那么实现很简单,只需调用InternetReadFile()一次,并期望单个返回立即或异步读取整个请求的缓冲区。这是使用此功能的正确方法,还是 MSDN 示例代码忽略了InternetReadFile()仅读取部分请求缓冲区的可能性?

4

2 回答 2

3

在更仔细地阅读异步示例之后,我现在看到它正在重复读取,直到遇到成功读取 0 字节。因此,要回答我自己的问题,您必须一遍又一遍地调用 InternetReadFile(),并为同步或异步响应做好准备。

于 2013-04-01T18:37:09.730 回答
3

重复读取InternetReadFile()直到它返回 TRUE 并且 BytesRead 为 0 是正确的使用方法InternetReadFile(),但如果您异步工作还不够。

正如 MSDN 所说

异步运行时,如果对 InternetReadFile 的调用未导致事务完成,它将返回 FALSE,随后对 GetLastError 的调用将返回 ERROR_IO_PENDING。当事务完成时,在先前对 InternetSetStatusCallback 的调用中指定的 InternetStatusCallback 将使用 INTERNET_STATUS_REQUEST_COMPLETE 调用。

因此,如果您在异步模式下工作,InternetReadFile()可能会返回FALSE并将最后一个错误设置为value。ERROR_IO_PENDING

InternetSetStatusCallback将再次调用时INTERNET_STATUS_REQUEST_COMPLETElpvStatusInformation参数将包含INTERNET_ASYNC_RESULT结构的地址(参见InternetStatusCallback 回调函数)。该INTERNET_ASYNC_RESULT.dwResult成员将包含异步操作的结果(TRUEFALSE自您调用以来InternetReadFile),并且仅当isINTERNET_ASYNC_RESULT.dwError时才会包含错误代码。dwResultFALSE

如果dwResult是,TRUE那么您Buffer包含从 Internet 读取的数据,并且BytesRead包含异步读取的字节数。

所以当你异步工作时最重要的事情之一是调用Buffer之间BytesRead 必须保持InternetStatusCallback不变,即不能在堆栈上分配。否则它有未定义的行为,导致内存损坏等。

于 2014-04-07T06:12:49.820 回答