WinInet和winHttp库使用简介

1 篇文章 0 订阅

初始化

InternetOpen

HINTERNET InternetOpen(
  LPCSTR lpszAgent,
  DWORD  dwAccessType,
  LPCSTR lpszProxyName,
  LPCSTR lpszProxyBypass,
  DWORD  dwFlags
);

"InternetOpen"是Windows操作系统提供的函数之一,位于WinINet库中。它用于初始化WinINet网络会话,并返回一个用于后续网络操作的句柄。

参数说明:

  • lpszAgent: 一个指向字符串的指针,表示应用程序名称或标识符,用于标识创建的会话。
  • dwAccessType: 指定访问类型,可以是以下几个值之一:
    • INTERNET_OPEN_TYPE_PRECONFIG`: 使用系统配置的代理设置。
    • INTERNET_OPEN_TYPE_DIRECT: 直接连接到互联网。
    • INTERNET_OPEN_TYPE_PROXY: 使用指定的代理设置。
    • INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY: 使用系统配置的代理设置,但不自动检测自动代理设置。
  • lpszProxyName: 一个指向字符串的指针,表示使用的代理服务器名称。
  • lpszProxyBypass: 一个指向字符串的指针,表示不使用代理的地址。
  • dwFlags:一些选项标志,可以是0或以下值的组合:
    • INTERNET_FLAG_ASYNC: 异步模式,表示启用异步操作。在异步模式下,函数将立即返回而不阻塞当前线程,并通过回调函数来处理请求的结果和状态。
    • INTERNET_FLAG_FROM_CACHE: 如果可用,从缓存中获取数据。
    • INTERNET_FLAG_OFFLINE: 无网络连接时,从缓存中获取数据。

返回值:

  • 成功时,返回一个有效的HINTERNET句柄,用于后续的网络操作。
  • 失败时,返回NULL,可以通过调用GetLastError()获取错误代码。

使用InternetOpen函数是进行网络操作的第一步,它初始化了一个网络会话,然后可以通过后续的WinINet函数来进行HTTP请求、FTP传输、下载文件等网络操作。

InternetSetStatusCallback

InternetSetStatusCallback是Windows操作系统提供的函数之一,位于WinINet库中。它用于为异步的WinINet操作设置回调函数,以便在操作状态发生变化时接收通知。

INTERNET_STATUS_CALLBACK InternetSetStatusCallback(
  HINTERNET                 hInternet,
  INTERNET_STATUS_CALLBACK lpfnInternetCallback
);

参数说明:

  • hInternet: 要设置回调函数的网络会话或请求句柄。

  • lpfnInternetCallback: 回调函数指针,指向用于接收回调通知的函数。回调函数必须符合INTERNET_STATUS_CALLBACK类型的定义。

    • 回调函数的定义如下:
    void CALLBACK InternetStatusCallback(
      HINTERNET hInternet,
      DWORD_PTR dwContext,
      DWORD     dwInternetStatus,
      LPVOID    lpvStatusInformation,
      DWORD     dwStatusInformationLength
    );
    
    

    参数说明:

    • hInternet: 引发状态回调的网络会话或请求句柄。

    • dwContext: 在调用InternetSetStatusCallback时传递的上下文参数。

    • dwInternetStatus: 表示引发回调的状态类型,具体取决于WinINet操作的不同阶段和情况。

    • lpvStatusInformation: 指向一个包含有关状态的信息的缓冲区。

    • dwStatusInformationLength: 缓冲区的大小。

    • 回调函数的主要作用是接收WinINet异步操作的状态变化通知,例如请求的进度、连接状态、错误信息等。在设置了回调函数后,当相应的操作状态发生变化时,系统会自动调用回调函数并传递相关的状态信息。

    通过设置回调函数,可以在异步操作中实现非阻塞的网络请求,提高程序的并发性和响应性。回调函数中可以根据不同的状态类型,采取相应的操作,比如处理请求结果、更新进度、处理错误等。

    需要注意的是,使用异步操作时,需要仔细处理回调函数的调用时机和回调数据的有效性,以确保程序的正确性和稳定性。

CRITICAL_SECTION

CRITICAL_SECTION 是 Windows API 中用于创建临界区(Critical Section)的数据结构。临界区是一种用于线程同步的机制,它可以确保在多线程环境下,只有一个线程可以进入被锁定的临界区代码段,从而实现对共享资源的互斥访问。

CRITICAL_SECTION 是一个临界区对象,使用前需要进行初始化,可以通过以下两种方式进行初始化:

  1. 使用 InitializeCriticalSection 函数进行初始化:
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
  1. 使用 InitializeCriticalSectionAndSpinCount 函数进行初始化,并指定自旋次数:
CRITICAL_SECTION cs;
InitializeCriticalSectionAndSpinCount(&cs, 4000); // 指定自旋次数,比如4000

CreateEvent

CreateEvent 是 Windows API 中用于创建一个事件对象的函数。事件对象是用于线程间通信和同步的一种内核对象,它可以用于多个线程之间的同步或线程的等待操作。

HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes,
  BOOL                  bManualReset,
  BOOL                  bInitialState,
  LPCTSTR               lpName
);

参数说明:

  • lpEventAttributes: 一个指向SECURITY_ATTRIBUTES结构的指针,用于指定事件对象的安全属性。可以为NULL,表示使用默认安全属性。
  • bManualReset: 一个BOOL值,用于指定事件是否为手动重置。如果为TRUE,则事件需要手动调用 ResetEvent 函数来重置为非信号状态;如果为FALSE,则事件会在有一个线程等待它时自动重置为非信号状态。
  • bInitialState: 一个BOOL值,用于指定事件的初始状态。如果为TRUE,则事件初始为有信号状态;如果为FALSE,则事件初始为无信号状态。
  • lpName: 一个指向以NULL结尾的字符串的指针,用于指定事件的名称。可以为NULL,表示事件没有名称。

CreateEvent 函数创建一个事件对象并返回一个句柄,可以用于后续操作。通常情况下,可以通过 SetEvent 函数将事件设置为有信号状态,通过 ResetEvent 函数将事件设置为无信号状态。线程可以调用 WaitForSingleObjectWaitForMultipleObjects 函数来等待事件对象。

需要注意的是,当不再使用事件对象时,应该通过 CloseHandle 函数关闭句柄,以释放资源:

CloseHandle(hEvent);

InternetConnect

InternetConnect 是 Windows API 中的一个函数,位于 WinINet 库中,用于在客户端应用程序中建立到远程服务器的连接。

HINTERNET InternetConnect(
  HINTERNET     hInternet,
  LPCTSTR       lpszServerName,
  INTERNET_PORT nServerPort,
  LPCTSTR       lpszUserName,
  LPCTSTR       lpszPassword,
  DWORD         dwService,
  DWORD         dwFlags,
  DWORD_PTR     dwContext
);

参数说明:

  • hInternet: 网络会话句柄,通常是通过 InternetOpen 函数返回的。
  • lpszServerName: 服务器的名称或 IP 地址,可以是一个以 NULL 结尾的字符串。
  • nServerPort: 服务器的端口号。
  • lpszUserName: 连接服务器所需的用户名,可以为 NULL。
  • lpszPassword: 连接服务器所需的密码,可以为 NULL。
  • dwService: 服务类型,通常使用 INTERNET_SERVICE_HTTPINTERNET_SERVICE_FTP 来指定 HTTP 或 FTP 服务。
  • dwFlags: 连接选项标志,可以使用 INTERNET_FLAG_PASSIVE 等来指定连接选项。
  • dwContext: 用户定义的上下文参数,将在回调函数中使用。

InternetConnect 函数用于建立与远程服务器的连接。它会返回一个连接句柄,用于后续的网络操作,如发送请求、下载数据等。

需要注意的是,在使用 WinINet API 进行网络操作时,需要先调用 InternetOpen 函数打开一个网络会话,再通过 InternetConnect 函数建立连接,最后使用其他相关函数来发送请求和接收响应。

同时,在使用完网络操作后,需要通过 InternetCloseHandle 函数关闭相关的句柄,以释放资源和确保程序的稳定性。

HttpOpenRequest

HttpOpenRequest 是 Windows API 中的一个函数,位于 WinINet 库中,用于创建一个 HTTP 请求句柄,以发送 HTTP 请求并接收服务器的响应。

HINTERNET HttpOpenRequest(
  HINTERNET hConnect,
  LPCTSTR   lpszVerb,
  LPCTSTR   lpszObjectName,
  LPCTSTR   lpszVersion,
  LPCTSTR   lpszReferrer,
  LPCTSTR   *lplpszAcceptTypes,
  DWORD     dwFlags,
  DWORD_PTR dwContext
);

参数说明:

  • hConnect: 已建立的连接句柄,通常是通过 InternetConnect 函数返回的。
  • lpszVerb: HTTP 请求的动作,例如 “GET”、“POST” 等。
  • lpszObjectName: 请求的对象,通常是请求的资源的路径。
  • lpszVersion: HTTP 协议的版本,例如 “HTTP/1.1”。
  • lpszReferrer: 引用页,通常是一个前一个页面的 URL。
  • lplpszAcceptTypes: 可接受的 MIME 类型数组。
  • dwFlags: 请求选项标志,可以使用 INTERNET_FLAG_SECURE 等来指定请求选项。
  • dwContext: 用户定义的上下文参数,将在回调函数中使用。

HttpOpenRequest 函数用于创建一个 HTTP 请求句柄,并返回该句柄用于后续的网络操作,如发送请求、接收响应等。

需要注意的是,在使用 WinINet API 进行 HTTP 请求时,需要先打开一个网络会话,然后建立连接,再创建请求句柄,最后使用其他相关函数来发送请求和接收响应。

同时,在使用完 HTTP 请求后,需要通过 InternetCloseHandle 函数关闭相关的句柄,以释放资源和确保程序的稳定性。

EnterCriticalSection

EnterCriticalSection 是 Windows API 中的一个函数,用于进入一个临界区(Critical Section)。临界区是一种同步机制,用于保护共享资源,防止多个线程同时访问和修改共享资源而导致数据不一致或竞争条件。

void EnterCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);

参数 lpCriticalSection 是一个指向临界区对象的指针,通常是 CRITICAL_SECTION 类型的指针。临界区对象需要先进行初始化,可以使用 InitializeCriticalSection 函数来初始化。

使用方法示例:

CRITICAL_SECTION cs; // 定义一个临界区对象
InitializeCriticalSection(&cs); // 初始化临界区对象

// 在需要保护共享资源的地方,进入临界区
EnterCriticalSection(&cs);
// 访问和修改共享资源的代码
// ...
// 离开临界区
LeaveCriticalSection(&cs);

InternetCloseHandle

InternetCloseHandle 是 Windows API 中的一个函数,位于 WinINet 库中,用于关闭由 WinINet API 创建的句柄。

BOOL InternetCloseHandle(
  HINTERNET hInternet
);

参数 hInternet 是需要关闭的句柄。该句柄可以是通过 InternetOpenInternetConnectHttpOpenRequest 等函数创建的,用于进行网络操作。

调用 InternetCloseHandle 函数后,系统会释放相应的资源,并将句柄置为无效。

WaitForSingleObject

WaitForSingleObject 是 Windows API 中的一个函数,用于等待一个对象(如线程、进程、事件等)进入有信号状态或超时。该函数是用于多线程编程中的同步机制。

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD  dwMilliseconds
);

参数说明:

  • hHandle: 要等待的对象的句柄。
  • dwMilliseconds: 等待的超时时间,以毫秒为单位。如果设置为 INFINITE,表示无限等待,直到对象进入有信号状态。

WaitForSingleObject 函数将等待指定的对象进入有信号状态,即该对象完成了某个操作或事件发生。当对象进入有信号状态时,函数返回 WAIT_OBJECT_0,表示成功等待到了对象的信号。如果在指定的超时时间内对象没有进入有信号状态,则函数返回 WAIT_TIMEOUT

HttpSendRequest

HttpSendRequest 是 Windows API 中的一个函数,位于 WinINet 库中,用于向服务器发送 HTTP 请求。

BOOL HttpSendRequest(
  HINTERNET hRequest,
  LPCWSTR   lpszHeaders,
  DWORD     dwHeadersLength,
  LPVOID    lpOptional,
  DWORD     dwOptionalLength
);

参数说明:

  • hRequest: HTTP 请求句柄,通过调用 HttpOpenRequest 函数返回。
  • lpszHeaders: 指向包含请求头的字符串指针,可以为 NULL。
  • dwHeadersLength: 请求头字符串的长度,如果 lpszHeaders 为 NULL,则该参数应该为 0。
  • lpOptional: 指向包含请求体的缓冲区指针,可以为 NULL。
  • dwOptionalLength: 请求体缓冲区的大小,如果 lpOptional 为 NULL,则该参数应该为 0。

HttpSendRequestEx

HttpSendRequestEx 是 Windows API 中的一个函数,位于 WinINet 库中,用于向服务器发送 HTTP 请求并接收服务器的响应。它与 HttpSendRequest 类似,但提供了更多的控制和扩展选项。

BOOL HttpSendRequestEx(
  HINTERNET            hRequest,
  LPINTERNET_BUFFERS   lpBuffersIn,
  LPINTERNET_BUFFERS   lpBuffersOut,
  DWORD                dwFlags,
  DWORD_PTR            dwContext
);

HttpSendRequestEx 是 Windows API 中的一个函数,位于 WinINet 库中,用于向服务器发送 HTTP 请求并接收服务器的响应。它与 HttpSendRequest 类似,但提供了更多的控制和扩展选项。

函数原型如下:

cppCopy codeBOOL HttpSendRequestEx(
  HINTERNET            hRequest,
  LPINTERNET_BUFFERS   lpBuffersIn,
  LPINTERNET_BUFFERS   lpBuffersOut,
  DWORD                dwFlags,
  DWORD_PTR            dwContext
);

参数说明:

  • hRequest: HTTP 请求句柄,通过调用 HttpOpenRequest 函数返回。

  • lpBuffersIn: 指向一个 INTERNET_BUFFERS 结构体的指针,用于设置请求数据的缓冲区。

  • lpBuffersOut: 指向一个 INTERNET_BUFFERS 结构体的指针,用于接收服务器响应数据的缓冲区。

  • dwFlags
    

    : 指定请求的标志,可以为以下常量的组合:

    • INTERNET_FLAG_RELOAD: 强制从服务器获取资源,忽略本地缓存。
    • INTERNET_FLAG_NO_CACHE_WRITE: 不将资源添加到本地缓存。
    • INTERNET_FLAG_FORMS_SUBMIT: 将请求用于 HTML 表单的提交。
    • 其他标志,具体可参考官方文档。
  • dwContext: 用户定义的上下文参数,将在异步操作时传递给回调函数。

HttpSendRequestEx 函数用于向服务器发送 HTTP 请求,并接收服务器的响应。通过 lpBuffersInlpBuffersOut 参数,可以设置请求的数据和接收服务器的响应数据。在调用该函数后,可以使用 InternetReadFile 函数来读取服务器返回的数据。

使用方法示例:

HINTERNET hInternet = InternetOpen(...); // 打开一个 Internet 会话
HINTERNET hConnect = InternetConnect(hInternet, ...); // 建立到服务器的连接
HINTERNET hRequest = HttpOpenRequest(hConnect, ...); // 创建一个 HTTP 请求句柄

INTERNET_BUFFERS buffersIn = { 0 }; // 设置请求数据的缓冲区
// 在 buffersIn 中设置请求数据的相关信息

INTERNET_BUFFERS buffersOut = { 0 }; // 接收服务器响应数据的缓冲区
// 在 buffersOut 中设置接收数据的相关信息

// 发送 HTTP 请求并接收服务器的响应
BOOL bSend = HttpSendRequestEx(hRequest, &buffersIn, &buffersOut, dwFlags, dwContext);

if (bSend) {
    // 请求发送成功并接收到服务器的响应,可以继续处理服务器响应数据
    // 使用 InternetReadFile 函数读取服务器返回的数据
} else {
    // 请求发送失败,可以根据 GetLastError 获取错误代码进行相应的处理
}

// 关闭句柄,释放资源
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);

ReadFile

ReadFile 是 Windows API 中的一个函数,位于 kernel32.dll 中,用于从文件、管道、字符设备等对象中读取数据。

BOOL ReadFile(
  HANDLE       hFile,
  LPVOID       lpBuffer,
  DWORD        nNumberOfBytesToRead,
  LPDWORD      lpNumberOfBytesRead,
  LPOVERLAPPED lpOverlapped
);

参数说明:

  • hFile: 要读取的文件、管道或设备的句柄。
  • lpBuffer: 指向用于存储读取数据的缓冲区。
  • nNumberOfBytesToRead: 要读取的字节数。
  • lpNumberOfBytesRead: 指向一个变量,用于接收实际读取的字节数。
  • lpOverlapped: 用于异步操作的 OVERLAPPED 结构体指针,可设置为 NULL 表示使用同步操作。

ReadFile 函数用于从指定的文件、管道或设备中读取数据,并将读取的数据存储到指定的缓冲区中。如果读取成功,则返回 TRUE,并通过 lpNumberOfBytesRead 参数返回实际读取的字节数。如果读取失败,则返回 FALSE,并可以通过调用 GetLastError 函数获取错误代码。

使用方法示例:

#include <Windows.h>

int main() {
    HANDLE hFile = CreateFile(L"C:\\path\\to\\file.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        // 处理文件打开失败的情况
        return -1;
    }

    char buffer[1024];
    DWORD bytesRead = 0;

    if (ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL)) {
        // 读取成功,bytesRead 中存储了实际读取的字节数
        // 可以对 buffer 中的数据进行处理
    } else {
        // 读取失败,可通过 GetLastError 获取错误代码
    }

    CloseHandle(hFile);
    return 0;
}

InternetWriteFile

InternetWriteFile 是 Windows API 中的一个函数,位于 WinINet 库中,用于向服务器发送 HTTP 请求的主体数据。

BOOL InternetWriteFile(
  HINTERNET hFile,
  LPCVOID   lpBuffer,
  DWORD     dwNumberOfBytesToWrite,
  LPDWORD   lpdwNumberOfBytesWritten
);

参数说明:

  • hFile: HTTP 请求句柄,通过调用 HttpOpenRequest 函数返回。
  • lpBuffer: 指向包含要发送的数据的缓冲区指针。
  • dwNumberOfBytesToWrite: 要发送的数据的字节数。
  • lpdwNumberOfBytesWritten: 指向一个变量,用于接收实际写入的字节数。

InternetWriteFile 函数用于向服务器发送 HTTP 请求的主体数据,即请求体。在调用该函数时,需要先调用 HttpOpenRequest 函数创建一个 HTTP 请求句柄,并通过 InternetConnect 函数建立到服务器的连接。

使用方法示例:

HINTERNET hInternet = InternetOpen(...); // 打开一个 Internet 会话
HINTERNET hConnect = InternetConnect(hInternet, ...); // 建立到服务器的连接
HINTERNET hRequest = HttpOpenRequest(hConnect, ...); // 创建一个 HTTP 请求句柄

const char* requestData = "This is the request data.";
DWORD requestDataSize = strlen(requestData);
DWORD bytesWritten = 0;

// 发送 HTTP 请求的主体数据
BOOL bWrite = InternetWriteFile(hRequest, requestData, requestDataSize, &bytesWritten);

if (bWrite) {
    // 请求体数据发送成功,可以继续处理服务器的响应数据
} else {
    // 请求体数据发送失败,可以根据 GetLastError 获取错误代码进行相应的处理
}

// 关闭句柄,释放资源
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);

HttpEndRequest

HttpEndRequest 是 Windows API 中的一个函数,位于 WinINet 库中,用于结束 HTTP 请求并接收服务器的响应。

BOOL HttpEndRequest(
  HINTERNET hRequest,
  LPINTERNET_BUFFERS lpBuffersOut,
  DWORD dwFlags,
  DWORD_PTR dwContext
);

参数说明:

  • hRequest: HTTP 请求句柄,通过调用 HttpOpenRequest 函数返回。

  • lpBuffersOut: 指向一个 INTERNET_BUFFERS 结构体的指针,用于接收服务器响应数据的缓冲区。

  • dwFlags
    

    : 指定结束请求的标志,可以为以下常量的组合:

    • INTERNET_NO_CALLBACK: 不使用回调函数。
    • INTERNET_FLAG_KEEP_CONNECTION: 在完成请求后保持与服务器的连接。
    • INTERNET_FLAG_SECURE: 使用 SSL 连接。
    • 其他标志,具体可参考官方文档。
  • dwContext: 用户定义的上下文参数,将在异步操作时传递给回调函数。

HttpEndRequest 函数用于结束 HTTP 请求并接收服务器的响应。在调用该函数后,可以通过 lpBuffersOut 参数接收服务器返回的数据。在调用 HttpSendRequestHttpSendRequestEx 函数后,应该使用 HttpEndRequest 函数来结束请求,以确保请求被正确发送给服务器并接收响应。

WriteFile

WriteFile 是 Windows API 中的一个函数,位于 kernel32.dll 中,用于向文件、管道、字符设备等对象中写入数据。

BOOL WriteFile(
  HANDLE       hFile,
  LPCVOID      lpBuffer,
  DWORD        nNumberOfBytesToWrite,
  LPDWORD      lpNumberOfBytesWritten,
  LPOVERLAPPED lpOverlapped
);

参数说明:

  • hFile: 要写入数据的文件、管道或设备的句柄。
  • lpBuffer: 指向包含要写入数据的缓冲区。
  • nNumberOfBytesToWrite: 要写入的字节数。
  • lpNumberOfBytesWritten: 指向一个变量,用于接收实际写入的字节数。
  • lpOverlapped: 用于异步操作的 OVERLAPPED 结构体指针,可设置为 NULL 表示使用同步操作。

WriteFile 函数用于向指定的文件、管道或设备中写入数据,并将指定的数据写入到缓冲区中。如果写入成功,则返回 TRUE,并通过 lpNumberOfBytesWritten 参数返回实际写入的字节数。如果写入失败,则返回 FALSE,并可以通过调用 GetLastError 函数获取错误代码。

使用方法示例:

#include <Windows.h>

int main() {
    HANDLE hFile = CreateFile(L"C:\\path\\to\\file.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        // 处理文件打开失败的情况
        return -1;
    }

    const char* dataToWrite = "Hello, WriteFile!";
    DWORD dataSize = strlen(dataToWrite);
    DWORD bytesWritten = 0;

    if (WriteFile(hFile, dataToWrite, dataSize, &bytesWritten, NULL)) {
        // 写入成功,bytesWritten 中存储了实际写入的字节数
    } else {
        // 写入失败,可通过 GetLastError 获取错误代码
    }

    CloseHandle(hFile);
    return 0;
}

SetEvent

SetEvent 是 Windows API 中的一个函数,位于 kernel32.dll 中,用于将指定的事件对象的状态设置为 signaled(即触发状态)。

BOOL SetEvent(
  HANDLE hEvent
);

参数说明:

  • hEvent: 要设置为 signaled 状态的事件对象的句柄。

SetEvent 函数用于将指定的事件对象的状态设置为 signaled。如果事件对象的初始状态为非 signaled(未触发状态),则调用 SetEvent 函数后,事件对象的状态会变为 signaled(触发状态),从而可以通知等待该事件对象的线程,使其继续执行。

使用方法示例:

#include <Windows.h>

int main() {
    // 创建一个自动重置的事件对象
    HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (hEvent == NULL) {
        // 处理事件对象创建失败的情况
        return -1;
    }

    // 等待事件对象的状态变为 signaled
    WaitForSingleObject(hEvent, INFINITE);

    // 继续执行其他操作

    CloseHandle(hEvent);
    return 0;
}

WinHttp简介:

什么是WinHttp?

Microsoft Windows HTTP Services (WinHTTP) 提供服务器支持的 HTTP/2 和 1.1 Internet 协议的高级接口。 WinHTTP 主要用于与 HTTP 服务器通信的服务器应用程序在基于服务器的方案中。

API的使用步骤如下:

在这里插入图片描述

封装类

编译器使用的是vs2019,然后json库和编码转换以及类之间的通信使用的是Qt的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XQgpmpKA-1693216132597)(…\Image\企业微信截图_20230814161504.png)]

WinHttpRequest类是提供给调用者使用的,WinHttpThread则是实际发送http请求的地方;

大致流程如下:

main
WinHttpRequest
WinHttpThread

调用者将所需参数传入winHttpRequest中,WinHttpRequest将参数转换后传入WinHttpThread中,如果指定的是异步则会创建一个线程,并将此线程传入线程池中,如果不是则会同步堵塞当前线程。在WinHttpThread中http处理完成后则会将信息传回到WinHttpRequest中,由WinHttpRequest通知调用者http返回的结果;

WinHttpRequest.h

#pragma once
#include <QObject>
#include <QThreadPool>
#include "WinHttpThread.h"


class WinHttpRequest :
    public QObject
{
    Q_OBJECT
public:
    enum CONNECTIO_ACTION
    {        
        SYNCHRONOUS,
        ASYNCHRONOUS,
    };
    Q_ENUM(CONNECTIO_ACTION)

    WinHttpRequest(QObject *parent=nullptr);
    ~WinHttpRequest();
    static WinHttpRequest* getInstance();
    /// <summary>
    /// 开始Http请求
    /// </summary>
    /// <param name="url">资源路径</param>
    /// <param name="headetContentType">告知服务端文本格式</param>
    /// <param name="model">请求谓词</param>
    /// <param name="requestType">用来表示每一个http请求的枚举值</param>
    /// <param name="params">body中传入的参数</param>
    /// <param name="connection">同步或异步</param>
    void httpRequest(const QString url, const QString headetContentType = "", const WinHttpThread::HttpRequestMode model = WinHttpThread::GET, const WinHttpThread::HttpRequestType requestType = WinHttpThread::HTTP_REQUEST_LOGIN, const QVariantMap params = {}, CONNECTIO_ACTION connection = ASYNCHRONOUS);
public: signals:	
    void sigHttpRequestReply(int code, WinHttpThread::HttpRequestType requestType, QByteArray data);   
private:
	QThreadPool m_threadPool;
};


WinHttpRequest.cpp

#include "WinHttpRequest.h"
#include <iostream>
#include <strsafe.h>



WinHttpRequest::WinHttpRequest(QObject* parent)
	:QObject(parent)
{
	m_threadPool.setMaxThreadCount(3);
}

WinHttpRequest::~WinHttpRequest()
{
	m_threadPool.clear();
	m_threadPool.waitForDone(3000);
}

WinHttpRequest* WinHttpRequest::getInstance()
{
	static WinHttpRequest winHttpRequest;
	return &winHttpRequest;
}

void WinHttpRequest::httpRequest(const QString url, const QString headetContentType, const WinHttpThread::HttpRequestMode model, const WinHttpThread::HttpRequestType requestType, const QVariantMap params, CONNECTIO_ACTION connection) {

	if (connection == ASYNCHRONOUS) {
		WinHttpThread* thread = new WinHttpThread(url, headetContentType, model, requestType, params);
		connect(thread, &WinHttpThread::sigHttpRequested, this, [=](int code, WinHttpThread::HttpRequestType type, QByteArray recev) {
			qDebug() << "code:" << code << " type" << type << " recev" << QString::fromUtf8(recev);
			});
		m_threadPool.start(thread);
	}
	else {
		WinHttpThread thread(url, headetContentType, model, requestType, params);
		WinHttpThread::MsgData msgData;
		if (thread.doWork(msgData)) {
			qDebug() << "code:" << msgData.statuscode << " type:" << msgData.reqType << " recev" << QString::fromUtf8(msgData.data);
		}
	}	
}

WinHttpThread.h

#pragma once
#include <qobject.h>
#include <QThread>
#include <QRunnable>
#include <QObject>
#include <QVariantMap>
#include <QJsonDocument>
#include <windows.h>
#include <winhttp.h>
#include <QString>
#include <QThreadPool>
#include <mutex>

#pragma comment (lib,"Winhttp")

typedef struct URLData {
	QString hostName;
	QString resourceUrl;
	int port;
	URLData() {
		hostName = "";
		resourceUrl = "";
		port = INTERNET_DEFAULT_HTTP_PORT;
	}
}URLData_t;

class WinHttpThread :
    public QObject,public QRunnable
{
	Q_OBJECT
public:
	enum HttpRequestMode {
		GET,
		POST,
		HEAD,
		PUT,
		DELETE_N,
		CONNECT,
		OPTIONS,
		TRACE,
		DEFAULT
	};
	Q_ENUM(HttpRequestMode)

	enum HttpRequestType {
		HTTP_REQUEST_LOGIN,
		HTTP_REQUEST_USERCONFIG,
        HTTP_REQUEST_GETPAGE
	};
	Q_ENUM(HttpRequestType)

	typedef struct MsgData {
		DWORD statuscode;
		HttpRequestType reqType;
		QByteArray data;
	}MsgData_t;

	WinHttpThread() = delete;
    WinHttpThread(const QString url, const QString headetContentType = "", const HttpRequestMode model = GET, const HttpRequestType requestType = HTTP_REQUEST_LOGIN, const QVariantMap params = {});
    ~WinHttpThread();
	//时机处理http请求的地方
	bool doWork(MsgData& data);
public:signals:
	void sigHttpRequested(int code, HttpRequestType type, QByteArray recev);
protected:
	void init();
    void run();
	bool analyseUrl(const QString& url);
	template <typename T>
	void setRawHeader(QString key, T value);	
private:
	void addHeaderToHttp(HINTERNET &hRequest);
	LPCWSTR getReqModel(HttpRequestMode reqModel);
	void ReleaseHandle();
	
private:
    HINTERNET m_heSession;
    HINTERNET m_hConnect;
    HINTERNET m_hRequest;
	bool isInit = false;

	QMap<QString, QString> m_map;//header
	QVariantMap m_params;//body

	QString m_url = "";
	QString m_headerContentType = "";
	HttpRequestMode m_model;
	HttpRequestType m_requestType;	
	URLData_t m_urlData;
	const LPCWSTR m_appName = L"vlive";
	std::mutex m_mutex;
	QByteArray data;
};

WinHttpThread.cpp


#include "WinHttpThread.h"

WinHttpThread::WinHttpThread(const QString url, const QString headetContentType, const HttpRequestMode model, const HttpRequestType requestType, const QVariantMap params)
	:m_url(url),m_headerContentType(headetContentType),m_model(model),m_requestType(requestType), m_params(params)
{
	isInit = analyseUrl(m_url);
    //此处设置http头部内容
	m_map.insert("browser_kernel", "1.6.2");
	m_map.insert("device", "DDF935926350BAF0372FB0058DB22687CC75F03580B02FCDBC5D6A0B");
	m_map.insert("version", "1.6.2.0");
	m_map.insert("Content-type", headetContentType);
}

WinHttpThread::~WinHttpThread()
{	
	ReleaseHandle();
}

void WinHttpThread::init()
{
}

void WinHttpThread::run()
{	
	MsgData data;
	if (doWork(data)) {
		emit sigHttpRequested(data.statuscode, data.reqType, data.data);
	}	
	ReleaseHandle();	
}

bool WinHttpThread::analyseUrl(const QString& url)
{
	QUrl qurl(url);
	DWORD error;
	if (!qurl.isValid()) {
		qDebug() << "no vailed url." << url;
		return false;
	}
	m_urlData.hostName = qurl.host();
	m_urlData.resourceUrl = qurl.path();
	QString str = qurl.scheme();
	if (str == "https") {
		m_urlData.port = INTERNET_DEFAULT_HTTPS_PORT;
	}
	else if (str == "http") {
		m_urlData.port = INTERNET_DEFAULT_HTTP_PORT;
	}
	else {
		qDebug() << "unkonw url." << url;
		return false;
	}
	return true;
}

void WinHttpThread::addHeaderToHttp(HINTERNET& hRequest)
{
	if (!hRequest) {
		qDebug() << "hRequest is null...";
		return;
	}
	QMap<QString,QString>::const_iterator iteral;
	BOOL re = FALSE;
	QString data = "";
	std::wstring dataC = L"";
	DWORD error;
	for (iteral = m_map.cbegin(); iteral != m_map.cend(); iteral++) {
		data = iteral.key() + ": " + iteral.value();
		dataC = data.toStdWString();
		re = WinHttpAddRequestHeaders(hRequest, dataC.c_str(), dataC.size(), WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE);
		if (re) {
			error = GetLastError();
			qDebug() << "header:" << data << "error:" << error;			
		}
	}
}

LPCWSTR WinHttpThread::getReqModel(HttpRequestMode reqModel)
{
	switch (reqModel) {
	case GET:
		return L"GET";
		break;
	case POST:
		return L"POST";
		break;
	case PUT:
		return L"PUT";
		break;
	case DELETE_N:
		return L"DELETE";
		break;
	default:
		return L"";
		break;
	}
}

void WinHttpThread::ReleaseHandle()
{
	if (m_mutex.try_lock()) {
		if (m_hRequest)   WinHttpCloseHandle(m_hRequest);
		if (m_hConnect)   WinHttpCloseHandle(m_hConnect);
		if (m_heSession)   WinHttpCloseHandle(m_heSession);
		m_mutex.unlock();
	}	
}


bool WinHttpThread::doWork(MsgData& msgData) {
	if (!isInit)return false;
	DWORD error;
	m_heSession = WinHttpOpen(m_appName, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
		, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
	if (!m_heSession) {
		error = GetLastError();
		qDebug() << "WinHttpOpen:" << "error:" << error;
	}

	LPCWSTR model = getReqModel(m_model);

	m_hConnect = WinHttpConnect(m_heSession, m_urlData.hostName.toStdWString().c_str(), m_urlData.port, 0);
	if (!m_hConnect) {
		error = GetLastError();
		qDebug() << "WinHttpConnect error:" << error;
		ReleaseHandle();
		return false;
	}

	m_hRequest = WinHttpOpenRequest(m_hConnect, model, m_urlData.resourceUrl.toStdWString().c_str(), NULL, WINHTTP_NO_REFERER,
		WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
	if (!m_hRequest) {
		error = GetLastError();
		qDebug() << "WinHttpConnect error:" << error;
		ReleaseHandle();
		return false;
	}
	//body
	QByteArray byte = "";
	if (!m_params.isEmpty()) {
		byte = QJsonDocument::fromVariant(m_params).toJson().data();
	}
	//init httpheader
	addHeaderToHttp(m_hRequest);
	std::string strB = byte.toStdString();
    //send && init body
	if (!WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, (LPVOID)strB.c_str(), strB.size(), strB.size(), 0)) {
		error = GetLastError();
		qDebug() << "WinHttpSendRequest error:" << error;
		ReleaseHandle();
		return false;
	}

	if (!WinHttpReceiveResponse(m_hRequest, 0)) {
		error = GetLastError();
		qDebug() << "WinHttpReceiveResponse error:" << error;
		ReleaseHandle();
		return false;
	}

	//get status code
	DWORD statusCode;
	DWORD dwSize = sizeof(statusCode);
	DWORD recevicedSize;
	WinHttpQueryHeaders(m_hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
		WINHTTP_HEADER_NAME_BY_INDEX,
		&statusCode, &dwSize, WINHTTP_NO_HEADER_INDEX);

	//READ data
	LPSTR pszOutBuffer;
	QByteArray data;
	do {
		dwSize = 0;
		if (!WinHttpQueryDataAvailable(m_hRequest, &dwSize)) {
			error = GetLastError();
			qDebug() << "WinHttpQueryDataAvailable error:" << error;
			ReleaseHandle();
			return false;
		}
		else {
			pszOutBuffer = new char[dwSize + 1];
			if (!pszOutBuffer) {
				qDebug() << "out memory...";
				dwSize = 0;
			}
			else {
				ZeroMemory(pszOutBuffer, dwSize + 1);
                //读取处理的数据编码为uincode可能会乱码,需要转为utf-8。此处不转换,有外部转换
				if (!WinHttpReadData(m_hRequest, (LPVOID)pszOutBuffer,
					dwSize, &recevicedSize)) {
					error = GetLastError();
					qDebug() << "WinHttpQueryDataAvailable error:" << error;
					ReleaseHandle();
					delete[] pszOutBuffer;
					return false;
				}
				else {
					data.append(pszOutBuffer);
				}
				delete[] pszOutBuffer;
			}
		}
	} while (dwSize > 0);
	msgData.statuscode = statusCode;
	msgData.data = data;
	msgData.reqType = m_requestType;
	return true;
}

例子

 	QVariantMap params;
	params.insert("name", "hqluo");	
    WinHttpRequest::getInstance()->httpRequest("https://www.baidu.com"
        , "application/json", WinHttpThread::HttpRequestMode::GET,WinHttpThread::HttpRequestType::HTTP_REQUEST_GETPAGE, 		params,WinHttpRequest::ASYNCHRONOUS);
//此处我们将http的请求体中的内容设置为{"name":"hqluo"},并且告知服务端数据格式为json格式,以及模式设置为异步模式

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WinHTTP提供以下功能: WinHttpAddRequestHeaders 向HTTP请求句柄添加一个或多个HTTP请求标头。 WinHttpCheckPlatform 确定WinHTTP是否支持当前平台。 WinHttpCloseHandle 关闭单个 HINTERNET句柄。 WinHttpConnect 指定HTTP请求的初始目标服务器。 WinHttpCrackUrl 将URL分为其组成部分,例如主机名和路径。 WinHttpCreateProxyResolver 创建WinHttpGetProxyForUrlEx使用的句柄。 WinHttpCreateUrl 从组件部分创建URL,例如主机名和路径。 WinHttpDetectAutoProxyConfigUrl 查找代理自动配置(PAC)文件的URL。此功能报告PAC文件的URL,但不下载该文件。 WinHttpFreeProxyResult 释放从以前的调用WinHttpGetProxyResult检索的数据。 WinHttpGetDefaultProxyConfiguration 从注册表中检索默认的WinHTTP代理配置。 WinHTTPGetIEProxyConfigForCurrentUser 获取当前用户的Internet Explorer(IE)代理配置。 WinHttpGetProxyForUrl 检索指定URL的代理信息。 WinHttpGetProxyForUrlEx 检索指定URL的代理信息。 WinHttpGetProxyResult 检索到调用的结果WinHttpGetProxyForUrlEx。 WinHttpOpen 初始化应用程序对WinHTTP功能的使用WinHttpOpenRequest 创建HTTP请求句柄。 WinHttpQueryAuthSchemes 返回服务器支持的授权方案。 WinHttpQueryDataAvailable 返回可立即与读取数据的字节数 WinHttpReadData。 WinHttpQueryHeaders 检索与HTTP请求相关联的头信息。 WinHttpQueryOption 在指定的句柄上查询Internet选项。 WinHttpReadData 从WinHttpOpenRequest函数打开的句柄中读取数据 。 WinHttpReceiveResponse 结束由WinHttpSendRequest启动的HTTP请求 。 WinHttpResetAutoProxy 重置自动代理。 WinHttpSendRequest 将指定的请求发送到HTTP服务器。 WinHttpSetCredentials 将所需的授权凭证传递给服务器。 WinHttpSetDefaultProxyConfiguration 在注册表中设置默认的WinHTTP代理配置。 WinHttpSetOption 设置Internet选项。 WinHttpSetStatusCallback 设置WinHTTP可以在操作过程中进行调用的回调函数。 WinHttpSetTimeouts 设置涉及HTTP事务的各种超时。 WinHttpTimeFromSystemTime 根据HTTP版本1.0规范格式化日期和时间。 WinHttpTimeToSystemTime 获取HTTP时间/日期字符串并将其转换为 SYSTEMTIME结构。 WinHttpWriteData 将请求数据写入HTTP服务器。 WinHttpWebSocketClose 关闭WebSocket连接。 WinHttpWebSocketCompleteUpgrade 完成由WinHttpSendRequest启动的WebSocket握手。 WinHttpWebSocketQueryCloseStatus 获取服务器发送的关闭状态。 WinHttpWebSocketReceive 从WebSocket连接接收数据。 WinHttpWebSocketSend 通过WebSocket连接发送数据。 WinHttpWebSocketShutdown 向WebSocket连接发送关闭框架
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值