wininet异步InternetReadFile和超时相关问题

时间:2022-07-24 08:47:28

wininet是对socket的封装

主要流程为创建,连接,发送,接收,关闭几个过程

所以在回调函数InternetStatusCallback中可以检测到dwInternetStatus

#define INTERNET_STATUS_HANDLE_CREATED          60

#define INTERNET_STATUS_CONNECTING_TO_SERVER    20
#define INTERNET_STATUS_CONNECTED_TO_SERVER     21

#define INTERNET_STATUS_SENDING_REQUEST         30
#define INTERNET_STATUS_REQUEST_SENT            31

#define INTERNET_STATUS_RECEIVING_RESPONSE      40
#define INTERNET_STATUS_RESPONSE_RECEIVED       41

#define INTERNET_STATUS_REQUEST_COMPLETE        100

#define INTERNET_STATUS_CLOSING_CONNECTION      50
#define INTERNET_STATUS_CONNECTION_CLOSED       51

所以有的时候在设置超时时候不好用 因为只是设置了一个过程的超时整体超时还是不好用

如超时有

#define INTERNET_OPTION_CONNECT_TIMEOUT         2

#define INTERNET_OPTION_CONTROL_SEND_TIMEOUT    INTERNET_OPTION_SEND_TIMEOUT
#define INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT INTERNET_OPTION_RECEIVE_TIMEOUT
#define INTERNET_OPTION_DATA_SEND_TIMEOUT       7
#define INTERNET_OPTION_DATA_RECEIVE_TIMEOUT    8

应该设置各个流程的超时如:

InternetSetOption(NULL, INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT, &dwTimeout, sizeof(DWORD));

但是每个流程超时设置后应答时间和预期还是不一样。可能有几种原因,

1.各个流程不是按照最长流程超时返回,所以有的流程没有花费timeout超时已经返回

2.设置超时还不够完整 还有别的流程需要设置超时

3.设置超时失效http://support.microsoft.com/kb/176420也许是微软BUG

关于异步wininet网上都说要用InternetReadFileEx而不用InternetReadFile但是我试了一下两个函数其实一样只是参数不一样罢了
其实在使用该两个函数的时候经常会返回 重叠 I/O 操作在进行中的错误,是http缓冲区正在读数据。
 
当没调用一次InternetReadFile 就会发现回调函数发送一次INTERNET_STATUS_RECEIVING_RESPONSE  接收数据的信号
首先在InternetReadFile要取得读取的数据大小用 ret = HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH,  szContentLength, &length,&index); HTTP_QUERY_CONTENT_LENGTH为数据大小。
主要在收到回调的两个地方来调用InternetReadFile 一是 INTERNET_STATUS_REQUEST_COMPLETE 当数据量比较小的时候只需要读一次就可以返回
所有数据 但数据量比较大的时候需要等INTERNET_STATUS_RESPONSE_RECEIVED  通知,不论数据量多大只需要这两个过程足够,而不是想象的可以有多次
INTERNET_STATUS_RESPONSE_RECEIVED 
一个完整小数据量流程为:
#define INTERNET_STATUS_HANDLE_CREATED          60
#define INTERNET_STATUS_CONNECTING_TO_SERVER    20
#define INTERNET_STATUS_CONNECTED_TO_SERVER     21
#define INTERNET_STATUS_SENDING_REQUEST         30
#define INTERNET_STATUS_REQUEST_SENT            31
#define INTERNET_STATUS_RECEIVING_RESPONSE      40
#define INTERNET_STATUS_RESPONSE_RECEIVED       41
#define INTERNET_STATUS_REQUEST_COMPLETE        100
一个完整大数据量流程为:
#define INTERNET_STATUS_HANDLE_CREATED          60
#define INTERNET_STATUS_CONNECTING_TO_SERVER    20
#define INTERNET_STATUS_CONNECTED_TO_SERVER     21
#define INTERNET_STATUS_SENDING_REQUEST         30
#define INTERNET_STATUS_REQUEST_SENT            31
#define INTERNET_STATUS_RECEIVING_RESPONSE      40
#define INTERNET_STATUS_RESPONSE_RECEIVED       41
#define INTERNET_STATUS_REQUEST_COMPLETE        100
#define INTERNET_STATUS_RECEIVING_RESPONSE      40
#define INTERNET_STATUS_RESPONSE_RECEIVED       41
但大数据量比较大的时候就会出现一个问题:
分两个InternetReadFile怎么把HTTP_QUERY_CONTENT_LENGTH分成两块呢?
我试了多种方法:
1。InternetQueryDataAvailable(hRequest,&length,0,0);
取得可用数据长度但是失败了。
2.通过回调函数中的lpvStatusInformation取得数据还是不对
 
通过调用InternetReadFile会发现虽然返回值是错误(重叠 I/O 操作在进行中的错误)但是数据buffer中时有数据的也就是说已经读了一部分
最后经过调查和尝试发现前两种情况返回的长度不是读取的数据的长度而是取得字符串的长度,为查找'\0'结束符返回的长度。最后经过尝试发现
在第一次InternetReadFile把申请的HTTP_QUERY_CONTENT_LENGTH数据全部传入
在第二次InternetReadFile传入buffer+strlen(buffer1)惊奇的发现好用了。。。。