使用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

posted on 2023-08-01 20:20  dchao  阅读(634)  评论(0编辑  收藏  举报

导航