多线程并发 WinHttp
时间: 2023-06-28 11:11:56 浏览: 258
在 Windows 平台上,WinHttp 库提供了一种使用 HTTP 和 HTTPS 协议进行网络通信的方式。在多线程并发场景下,可以使用 WinHttp 提供的异步操作来实现并发请求。
以下是一个使用 WinHttp 实现多线程并发的示例代码:
```c++
#include <Windows.h>
#include <winhttp.h>
#include <vector>
#pragma comment(lib, "winhttp.lib")
struct WinHttpRequestInfo
{
HINTERNET hSession;
HINTERNET hConnect;
HINTERNET hRequest;
DWORD dwStatusCode;
std::vector<char> responseBuffer;
};
DWORD WINAPI WinHttpRequestThread(LPVOID lpParam)
{
WinHttpRequestInfo* pInfo = static_cast<WinHttpRequestInfo*>(lpParam);
// 发送请求
if (!WinHttpSendRequest(pInfo->hRequest, NULL, 0, NULL, 0, 0, NULL))
{
pInfo->dwStatusCode = GetLastError();
return 1;
}
// 接收响应头
if (!WinHttpReceiveResponse(pInfo->hRequest, NULL))
{
pInfo->dwStatusCode = GetLastError();
return 1;
}
// 获取响应状态码
DWORD dwStatusCode = 0;
DWORD dwSize = sizeof(DWORD);
if (!WinHttpQueryHeaders(pInfo->hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwStatusCode, &dwSize, NULL))
{
pInfo->dwStatusCode = GetLastError();
return 1;
}
pInfo->dwStatusCode = dwStatusCode;
// 接收响应体
const DWORD RESPONSE_BUFFER_SIZE = 1024;
DWORD dwBytesRead = 0;
do
{
char buffer[RESPONSE_BUFFER_SIZE] = { 0 };
if (!WinHttpReadData(pInfo->hRequest, buffer, RESPONSE_BUFFER_SIZE - 1, &dwBytesRead))
{
break;
}
pInfo->responseBuffer.insert(pInfo->responseBuffer.end(), buffer, buffer + dwBytesRead);
} while (dwBytesRead > 0);
return 0;
}
int main()
{
// 创建会话句柄
HINTERNET hSession = WinHttpOpen(L"WinHttp Example/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession)
{
return 1;
}
// 创建连接句柄
HINTERNET hConnect = WinHttpConnect(hSession, L"www.example.com", INTERNET_DEFAULT_HTTPS_PORT, 0);
if (!hConnect)
{
WinHttpCloseHandle(hSession);
return 1;
}
// 发送请求
std::vector<WinHttpRequestInfo> requestInfos(10);
for (size_t i = 0; i < requestInfos.size(); ++i)
{
requestInfos[i].hSession = hSession;
requestInfos[i].hConnect = hConnect;
requestInfos[i].hRequest = WinHttpOpenRequest(hConnect, L"GET", L"/", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_ASYNC);
if (!requestInfos[i].hRequest)
{
continue;
}
WinHttpSetStatusCallback(requestInfos[i].hRequest, [](HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength) {}, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL);
WinHttpSendRequest(requestInfos[i].hRequest, NULL, 0, NULL, 0, 0, reinterpret_cast<DWORD_PTR>(&requestInfos[i]));
WinHttpReceiveResponse(requestInfos[i].hRequest, NULL);
}
// 等待请求完成
HANDLE hEvents[requestInfos.size()] = { 0 };
for (size_t i = 0; i < requestInfos.size(); ++i)
{
hEvents[i] = WinHttpQueryDataAvailable(requestInfos[i].hRequest, NULL) ? CreateThread(NULL, 0, WinHttpRequestThread, &requestInfos[i], 0, NULL) : NULL;
}
WaitForMultipleObjects(requestInfos.size(), hEvents, TRUE, INFINITE);
// 输出响应状态码和响应内容
for (size_t i = 0; i < requestInfos.size(); ++i)
{
if (requestInfos[i].dwStatusCode == 200)
{
printf("%s\n", requestInfos[i].responseBuffer.data());
}
}
// 释放资源
for (size_t i = 0; i < requestInfos.size(); ++i)
{
if (requestInfos[i].hRequest)
{
WinHttpCloseHandle(requestInfos[i].hRequest);
}
}
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 0;
}
```
在这个示例代码中,我们使用 WinHttpOpen、WinHttpConnect 和 WinHttpOpenRequest 分别创建会话句柄、连接句柄和请求句柄。由于我们需要异步发送和接收请求,因此我们使用 WinHttpSetStatusCallback 函数设置回调函数,在回调函数中处理请求的结果。我们还使用 WinHttpQueryDataAvailable 函数来等待请求完成,并且对每个请求都创建一个线程来处理结果。
在使用 WinHttp 进行多线程并发时,需要注意以下几点:
1. 每个请求都需要一个独立的请求句柄。
2. 在使用异步操作时,需要使用回调函数来处理请求的结果。
3. 在等待请求完成时,可以使用 WinHttpQueryDataAvailable 函数来查询是否有数据可读。
4. 在使用多线程时,需要注意线程安全,例如共享资源的访问等。
希望这个示例代码能够帮助你了解如何使用 WinHttp 实现多线程并发。
阅读全文