C++ WinInet InternetCloseHandle 崩溃
Posted
技术标签:
【中文标题】C++ WinInet InternetCloseHandle 崩溃【英文标题】:C++ WinInet InternetCloseHandle crash 【发布时间】:2015-09-01 18:05:40 【问题描述】:我编写了一个使用 WinInet 库的程序。该程序每天运行约 8-12 小时。首先它连接到互联网,然后它使用 FTP 下载/上传文件。之后它开始一个循环,在不同的时间间隔内最多启动两个线程。两个线程都在向同一台服务器发送GET
-requests,看起来像这样:
private void Thread()
if(!InternetGetConnectedState(NULL, NULL))
connectToInternet();
// some code...
HINTERNET httpOpenRequest = HttpOpenRequest(
hHTTPConnection, // InternetConnect-Handle
L"GET", // HTTP-Verb
request_target, // FileName
L"HTTP/1.1", // HTTP-Version
NULL, // Referer
NULL, // AcceptTypes
INTERNET_FLAG_RELOAD, // Flags
0 // Context
);
BOOL httpsRequest = HttpSendRequest(
httpOpenRequest, // Handle of HttpOpenRequest
NULL, // Headers
0, // Headers-Length
NULL, // Optional
0 // Optional-Length
);
InternetCloseHandle(httpOpenRequest); // App-Crash sometimes here!
我的connectToInternet
-函数在这里:
int connectToInternet()
DWORD InetTest1 = 16000;
while (InetTest1 != 0)
InetTest1 = InternetAttemptConnect(0);
// wait 1 second for next attempt
if (InetTest1 != 0)
Sleep(1000);
BOOL InetTest2 = FALSE;
while (!InetTest2)
InetTest2 = InternetCheckConnection(
L"http://www.example.com", // URL
FLAG_ICC_FORCE_CONNECTION, // Flags
0 // Reserved
);
// wait 1 second for next attempt
if (!InetTest2)
Sleep(1000);
while (hInternetOpen == NULL)
hInternetOpen = InternetOpen(
L"Custom-Agent", // Agent
INTERNET_OPEN_TYPE_DIRECT, // AccessType
NULL, // ProxyName
NULL, // ProxyBypass
0 // Flags
);
// wait 1 second for next attempt
if (hInternetOpen == NULL)
Sleep(1000);
while (hHTTPConnection == NULL)
hHTTPConnection = InternetConnect(
hInternetOpen, // InternetOpen-Handle
L"www.example.com", // ServerName
INTERNET_DEFAULT_HTTP_PORT, // ServerPort
NULL, // Username
NULL, // Password
INTERNET_SERVICE_HTTP, // Service
0, // Flags
0 // Context
);
// wait 1 second for next attempt
if (hHTTPConnection == NULL)
Sleep(1000);
return 0;
(我在这里找到了这个函数的基本工作流程:https://msdn.microsoft.com/en-us/library/windows/desktop/aa383996(v=vs.85).aspx)
现在问题:
Q1:当两个线程之一调用InternetCloseHandle(httpOpenRequest)
时,我似乎很少遇到应用程序崩溃。我找不到这些应用崩溃的原因...您有什么想法吗?
Q2: 运行程序的笔记本电脑似乎存在互联网连接问题,因为它经常会在几秒钟到几分钟甚至几小时内失去连接。因此,如果InternetGetConnectedState(NULL, NULL)
是false
,我首先在两个线程中调用connectToInternet()
。是否需要此步骤,或者如果我不调用连接函数,它是否也可以工作?如果连接中断,全局HINTERNET
-Handles 是否无效?
[EDIT] 同时,我怀疑我的程序导致了连接问题,因为我在家中的有线网络上也没有互联网访问权限!我犯了什么错误吗?
【问题讨论】:
您在滥用GetLastError()
。除非首先报告实际失败(InternetOpen()
返回 NULL,InternetConnect()
返回 NULL 等),否则请勿调用它,否则您可能会看到早期 API 调用的错误代码,这些错误代码与您正在调用的 API 无关。除非明确记录,大多数 API 函数不会在输入时重置 GetLastError()
,或者如果成功则更新 GetLastError()
。
@RemyLebeau 好的,谢谢,我会针对这种误用修改我的程序代码!
@RemyLebeau 现在编辑了代码。关于错误的任何想法?
您有多个线程共享hInternetOpen
和hHTTPConnection
句柄,通过单个HTTP 连接在多个线程中发送HTTP 请求,而无需序列化对连接的访问。这是灾难的秘诀。因此,要么序列化对连接的访问以避免竞争条件,要么为每个线程提供自己的本地连接。
@RemyLebeau 好的,谢谢!如果我给每个线程自己的连接怎么样?如果同一个线程每 5 秒启动一次,会不会有问题?我所谓的“灾难食谱”会不会是问题 2 中所示的连接行为的原因?
【参考方案1】:
看来我的问题是多个线程同时运行并试图调用InternetCloseHandle()
引起的。
与此同时,我重写了我的代码。我还尝试让Remy Lebeau 的cmets 参与进来。我的代码现在看起来像以下示例:
void Thread()
// access-control
if (ThreadRunning == true)
return 99;
ThreadRunning = true;
// variables
HINTERNET hInternetOpen = NULL;
HINTERNET hHTTPConnection = NULL;
HINTERNET httpOpenRequest = NULL;
int connectionAttempts;
string target_string;
wstring target_wstring;
LPCWSTR request_target;
BOOL httpSendRequestSuccessful;
BOOL httpQueryInfoReceived;
DWORD statusCode = 0;
DWORD statusCodeLen = sizeof(statusCode);
BOOL dataAvailable;
DWORD numberOfBytesAvailable;
BOOL internetReadFileSuccessful;
char buffer[4096] = "" ;
DWORD numberOfBytesRead;
// Connect to Internet
connectionAttempts = 0;
DWORD InetTest1 = 16000;
while (InetTest1 != 0)
InetTest1 = InternetAttemptConnect(0);
if (InetTest1 != 0)
connectionAttempts++;
// prevent an infinite loop
if (connectionAttempts >= 5)
// reset access-control
ThreadRunning = false;
return 1;
// wait 1 second if it fails
Sleep(1000);
// reset connectionAttempts
connectionAttempts = 0;
BOOL InetTest2 = FALSE;
while (!InetTest2)
InetTest2 = InternetCheckConnection(
L"http://www.example.com", // URL
FLAG_ICC_FORCE_CONNECTION, // Flags
0 // Reserved
);
if (InetTest2 == FALSE)
connectionAttempts++;
// prevent an infinite loop
if (connectionAttempts >= 5)
// reset access-control
ThreadRunning = false;
return 2;
// wait 1 second if it fails
Sleep(1000);
// reset connectionAttempts
connectionAttempts = 0;
while (hInternetOpen == NULL)
hInternetOpen = InternetOpen(
L"Custom-Agent", // Agent
INTERNET_OPEN_TYPE_DIRECT, // AccessType
NULL, // ProxyName
NULL, // ProxyBypass
0 // Flags
);
if (hInternetOpen == NULL)
connectionAttempts++;
// prevent an infinite loop
if (connectionAttempts >= 5)
// reset access-control
ThreadRunning = false;
return 3;
// wait 1 second if it fails
Sleep(1000);
// reset connectionAttempts
connectionAttempts = 0;
while (hHTTPConnection == NULL)
hHTTPConnection = InternetConnect(
hInternetOpen, // InternetOpen-Handle
L"www.example.com", // ServerName
INTERNET_DEFAULT_HTTP_PORT, // ServerPort
NULL, // Username
NULL, // Password
INTERNET_SERVICE_HTTP, // Service
0, // Flags
0 // Context
);
if (hHTTPConnection == NULL)
connectionAttempts++;
// prevent an infinite loop
if (connectionAttempts >= 5)
// reset access-control
onlineSettingsThreadRunning = false;
// Handle-Cleanup
InternetCloseHandle(hInternetOpen);
return 4;
// wait 1 second if it fails
Sleep(1000);
// some code...
// open HTTP-Request
httpOpenRequest = HttpOpenRequest(
hHTTPConnection, // InternetConnect-Handle
L"GET", // HTTP-Verb (GET or POST)
request_target, // FileName
L"HTTP/1.1", // HTTP-Version
NULL, // Referer
NULL, // AcceptTypes
INTERNET_FLAG_RELOAD, // Flags
0 // Context
);
if (httpOpenRequest == NULL)
// Handle-Cleanup
InternetCloseHandle(hHTTPConnection);
InternetCloseHandle(hInternetOpen);
// reset access-control
onlineSettingsThreadRunning = false;
return 5;
// send HTTP-Request
httpSendRequestSuccessful = HttpSendRequest(
httpOpenRequest, // Handle von HttpOpenRequest
NULL, // Headers
0, // Headers-Length
NULL, // Optional
0 // Optional-Length
);
if (httpSendRequestSuccessful == FALSE)
// Handle-CleanUp
InternetCloseHandle(httpOpenRequest);
InternetCloseHandle(hHTTPConnection);
InternetCloseHandle(hInternetOpen);
// reset access-control
onlineSettingsThreadRunning = false;
return 6;
// read Server-Status
httpQueryInfoReceived = HttpQueryInfo(
httpOpenRequest,
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
&statusCode,
&statusCodeLen,
NULL
);
if (httpQueryInfoReceived == FALSE || statusCode != 200)
// Handle-CleanUp
InternetCloseHandle(httpOpenRequest);
InternetCloseHandle(hHTTPConnection);
InternetCloseHandle(hInternetOpen);
// reset access-control
onlineSettingsThreadRunning = false;
return 7;
// test, how much bytes are readable
dataAvailable = InternetQueryDataAvailable(
httpOpenRequest,
&numberOfBytesAvailable,
0,
0
);
if (dataAvailable == FALSE)
// Handle-CleanUp
InternetCloseHandle(httpOpenRequest);
InternetCloseHandle(hHTTPConnection);
InternetCloseHandle(hInternetOpen);
// reset access-control
onlineSettingsThreadRunning = false;
return 8;
// some code...
// Close internet-connection
InternetCloseHandle(httpOpenRequest);
InternetCloseHandle(hHTTPConnection);
InternetCloseHandle(hInternetOpen);
// reset access-control
ThreadRunning = false;
return 0;
所以我的connectToInternet()
-function 不再存在。它现在是需要互联网访问的每个线程的一部分。它也不再使用GetLastError()
,因为这可能会产生错误的结果...
我仍在测试我的代码,但它似乎很有希望:-)
【讨论】:
"它也不再使用 GetLastError(),因为这可能会产生错误的结果" - 只有当你错误地使用它时(你最初正在这样做)。跨度> @RemyLebeau 当然我的意思是我在我的第一个代码中使用该函数,而不是一般!以上是关于C++ WinInet InternetCloseHandle 崩溃的主要内容,如果未能解决你的问题,请参考以下文章