使用WinINet实现HTTP/HTTPS下载文件
环境:
Windows平台:Windows 10 专业版(64位)、VS2019
开始:
一、工具类
class internet
{
public:
internet(HINTERNET hInternet) : _internet(hInternet)
{
}
internet(internet&);
internet(const internet&);
~internet()
{
if (_internet) {
InternetCloseHandle(_internet);
_internet = nullptr;
}
}
internet& operator =(HINTERNET hInternet)
{
_internet = hInternet;
}
internet& operator =(internet&);
internet& operator =(const internet&);
operator HINTERNET()
{
return _internet;
}
operator bool() const
{
return _internet != nullptr;
}
protected:
HINTERNET _internet;
};
二、HTTP下载
int download_http(const char* address, const char* path, const char* user, const char* password, const char* filename)
{
// 创建会话
internet hSession = InternetOpenA("", INTERNET_OPEN_TYPE_DIRECT, nullptr, nullptr, 0);
if (!hSession) {
printf("create session failed,error=%d.", GetLastError());
return -1; // create session failed
}
// 设置超时时间
DWORD timeout = 10000;
InternetSetOption(hSession, INTERNET_OPTION_RECEIVE_TIMEOUT, &timeout, sizeof(timeout));
InternetSetOption(hSession, INTERNET_OPTION_CONNECT_TIMEOUT, &timeout, sizeof(timeout));
InternetSetOption(hSession, INTERNET_OPTION_SEND_TIMEOUT, &timeout, sizeof(timeout));
// 创建连接
internet hConnect = InternetConnectA(hSession, address, INTERNET_DEFAULT_HTTP_PORT, user, password, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect) {
printf("connect failed,address=%s,error=%d.", address, GetLastError());
return -2; // connect failed
}
// 创建请求
internet hRequest = HttpOpenRequestA(hConnect, "GET", path, HTTP_VERSION, "", nullptr, INTERNET_FLAG_KEEP_CONNECTION, 0);
if (!hRequest) {
printf("open request failed,address=%s%s,error=%d.", address, path, GetLastError());
return -3; // open request failed
}
// 发送请求
if (!HttpSendRequest(hRequest, nullptr, 0, nullptr, 0)) {
printf("send request failed,address=%s%s,error=%d.", address, path, GetLastError());
return -4; // send request failed
}
// 获取请求状态
DWORD dwStatus = HTTP_STATUS_OK;
DWORD dwStatusSize = sizeof(dwStatus);
HttpQueryInfo(hRequest, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE, &dwStatus, &dwStatusSize, nullptr);
if (dwStatus != HTTP_STATUS_OK) {
printf("http query failed,address=%s,error=%d.", address, dwStatus);
return -5; // http query failed
}
// 打开文件
std::ofstream out_file(filename, std::ios::binary);
if (!out_file.is_open()) {
printf("open file failed,address=%s,filename=%s,error=%d.", address, filename, GetLastError());
return -6; // open file failed
}
// 下载文件
int total = 0;
DWORD bytes = 0;
char buffer[1024]{ 0 };
while (InternetReadFile(hRequest, buffer, sizeof(buffer), &bytes) && bytes > 0) {
out_file.write(buffer, bytes);
total += bytes;
}
if (total < 1) {
printf("download file is empty,address=%s,filename=%s,size=%d.", address, filename, total);
return -7; // download file is empty
}
return 0;
}
使用:download_http("192.168.1.10", "/update/file", "user", "password", "test.txt")
三、HTTPS下载
int download_https(const char* address, const char* path, const char* user, const char* password, const char* filename)
{
// 创建会话
internet hSession = InternetOpenA("", INTERNET_OPEN_TYPE_DIRECT, nullptr, nullptr, 0);
if (!hSession) {
printf("create session failed,error=%d.", GetLastError());
return -1; // create session failed
}
// 设置超时时间
DWORD timeout = 10000;
InternetSetOption(hSession, INTERNET_OPTION_RECEIVE_TIMEOUT, &timeout, sizeof(timeout));
InternetSetOption(hSession, INTERNET_OPTION_CONNECT_TIMEOUT, &timeout, sizeof(timeout));
InternetSetOption(hSession, INTERNET_OPTION_SEND_TIMEOUT, &timeout, sizeof(timeout));
// 创建连接
internet hConnect = InternetConnectA(hSession, address, INTERNET_DEFAULT_HTTPS_PORT, user, password, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect) {
printf("connect failed,address=%s,error=%d.", address, GetLastError());
return -2; // connect failed
}
// 创建请求
internet hRequest = HttpOpenRequestA(hConnect, "GET", path, HTTP_VERSION, "", nullptr, INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE, 0);
if (!hRequest) {
printf("open request failed,address=%s%s,error=%d.", address, path, GetLastError());
return -3; // open request failed
}
// 发送请求
if (!HttpSendRequest(hRequest, nullptr, 0, nullptr, 0)) {
int error = GetLastError();
if (error == ERROR_INTERNET_INVALID_CA) {
DWORD dwFlags;
DWORD dwBuffLen = sizeof(dwFlags);
if (InternetQueryOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &dwBuffLen)) {
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
InternetSetOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof(dwFlags));
if (!HttpSendRequest(hRequest, nullptr, 0, nullptr, 0)) {
printf("send request failed,address=%s%s,error=%d.", address, path, GetLastError());
return -4; // send request failed
}
}
}
else {
printf("send request failed,address=%s%s,error=%d.", address, path, error);
return -4; // send request failed
}
}
// 获取请求状态
DWORD dwStatus = HTTP_STATUS_OK;
DWORD dwStatusSize = sizeof(dwStatus);
HttpQueryInfo(hRequest, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE, &dwStatus, &dwStatusSize, nullptr);
if (dwStatus != HTTP_STATUS_OK) {
printf("http query failed,address=%s,error=%d.", address, dwStatus);
return -5; // http query failed
}
// 打开文件
std::ofstream out_file(filename, std::ios::binary);
if (!out_file.is_open()) {
printf("open file failed,address=%s,filename=%s,error=%d.", address, filename, GetLastError());
return -6; // open file failed
}
// 下载文件
int total = 0;
DWORD bytes = 0;
char buffer[1024]{ 0 };
while (InternetReadFile(hRequest, buffer, sizeof(buffer), &bytes) && bytes > 0) {
out_file.write(buffer, bytes);
total += bytes;
}
if (total < 1) {
printf("download file is empty,address=%s,filename=%s,size=%d.", address, filename, total);
return -7; // download file is empty
}
return 0;
}
使用:download_https("192.168.1.10", "/update/file", "user", "password", "test.txt")
扩展:
1)WinINet处理身份验证:https://learn.microsoft.com/zh-cn/windows/win32/wininet/handling-authentication