WinInet库之Http通信
生活随笔
收集整理的這篇文章主要介紹了
WinInet库之Http通信
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
// 超文本傳輸協議(HyperText Transfer Protocol)是互聯網上應用最廣泛的協議,主要是用于網頁的瀏覽。
// HTTP采用了請求-應答模式,也就是俗稱的客戶端/服務器模型,簡稱C/S模型。
// 其中,客戶端向服務器發送一個請求,請求一般包括請求行、請求頭和請求體三個部分。
// 在請求頭中包含請求頭中包含請求方法、URL、協議版本以及請求修飾符,客戶消息和內容的類似于MIME的消息結構。
// 服務器以一個狀態作為響應,響應的內容包括消息協議的版本,成功或者錯誤編碼加上包含服務器信息、實體元信息以及可能的實體內容。// HTTP常用的請求方法有GET、POST、PUT、DELETE四個,對應著對網絡資源的查、改、增、刪四個操作。
// HTTP采用TCP通信,主要是保證傳輸數據的穩定性、完整性。// HTTP文件上傳,主要是向服務器發送POST請求,將數據按照服務器的接收格式傳輸到服務器上,服務器再根據接收格式接收數據,完成文件的上傳操作。
// HTTP文件下載,主要是向服務器發送GET請求,服務器接收到相應的請求后,便會讀取資源數據并返回,這就完成的文件下載操作。// PS:HttpOpenRequest函數:
// 功能:創建一個HTTP請求句柄。
// 原型:HINTERNET HttpOpenRequest(
// _In_ HINTERNET hConnect,
// _In_ LPCTSTR lpszVerb,
// _In_ LPCTSTR lpszObjectName,
// _In_ LPCTSTR lpszVersion,
// _In_ LPCTSTR lpszReferer,
// _In_ LPCTSTR *lplpszAcceptTypes,
// _In_ DWORD dwFlags,
// _In_ DWORD_PTR dwContext
// )
// 參數:hConnect:由InternetConnect函數返回的連接句柄。
// lpszVerb:請求的方法,默認為GET。
// lpszObjectName:目標對象字符串,通常為文件名稱、可自行模塊或者查找標識符。
// lpszVersion:HTTP版本,如果為NULL,表示使用1.1或1.0版本的HTTP協議。
// lpszReferer:指向URL文檔地址,如果為NULL,則不指定HTTP頭。
// lplpszAcceptTypes:表示客戶接受的內容類型,比如"text/json"等。
// dwFlags:標志,可以為以下值的一個或多個:
// INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP:禁用檢測這種特殊類型的重定向。
// INTERNET_FLAG_IGNORE_CERT_CN_INVALID:根據請求中給出的主機名禁用檢測從服務器返回的基于SSL/PCT的證書。
// INTERNET_FLAG_KEEP_CONNECTION:保持連接。
// INTERNET_FLAG_NO_AUTH:不會自動嘗試驗證。
// INTERNET_FLAG_NO_COOKIES:不會自動為請求添加Cookie標頭,也不會自動將返回的Cookie添加到Cookie數據庫。
// INTERNET_FLAG_NO_UI:禁用Cookie對話框。
// INTERNET_FLAG_RELOAD:強制從源服務器上下載所請求的文件,而不是從緩存中下載。
// INTERNET_FLAG_SECURE:啟用HTTPS。
// dwContext:指定OpenRequest操作的上下文標識。
// 結果:成功返回HTTP請求句柄,失敗返回NULL。// PS:HttpSendRequestEx函數:
// 功能:將指定的請求發送到HTTP服務器。
// 原型:BOOL HttpSendRequestEx(
// _In_ HINTERNET hRequest,
// _In_ LPINTERNET_BUFFERS lpBuffersIn,
// _Out_ LPINTERNET_BUFFERS lpBuffersOut,
// _In_ DWORD dwFlags,
// _In_ DWORD_PTR dwContext
// )
// 參數:hRequest:由HttpOpenRequest創建的請求句柄。
// lpBuufersIn:可選,指向INTERNET_BUFFERS結構的指針。
// lpBuffersOut:保留,必須為NULL。
// dwFlags:保留,必須為NULL。
// dwContext:指定由應用程序定義的上下文值,前提是狀態回調函數已注冊。
// 結果:成功返回TRUE,失敗返回FALSE。// PS:HttpQueryInfo函數:
// 功能:查詢有關HTTP請求的信息。
// 原型:BOOL WINAPI HttpQueryInfo(
// HINTERNET hRequest,
// DWORD dwInfoLevel,
// LPVOID lpBuffer,
// LPDWORD lpdwBufferLength,
// LPDWORD lpdwIndex
// )
// 參數:hRequest:由HttpOpenRequest函數創建的Request句柄。
// dwInfoLevel:請求要查詢的屬性和修改請求的標志組合。
// lpBuffer:接收信息的緩存區。
// lpdwBufferLength:接收緩存區大小。
// lpdwIndex:用于枚舉具有相同名稱的多個頭的基于零的頭索引。
// 結果:成功,返回TURE,失敗,返回FALSE。// PS:基于WinInet庫實現的HTTP文件上傳步驟如下:
// 1.調用InternetCrackUrl函數對Url進行分解,從URL中提取網站的域名、資源路徑、用戶名、密碼以及URL的附加信息等。
// 2.調用InternetOpen函數建立會話,獲取會話句柄。連接過程中要指明INTERNET_SERVICE_HTTP,這表明連接到HTTP服務器上。
// 3.調用InternetConnect函數建立連接,獲取連接句柄。
// 4.調用HttpOpenRequest打開HTTP的POST請求,同時指明POST的資源路徑,并且設置HTTP的訪問標志。
// 5.調用HttpSendRequestEx函數向服務器發送訪問請求。
// 6.調用InternetWriteFile函數將本地數據寫到遠程主機上,即向服務器上傳數據。等數據上傳完畢后,調用HttpEndRequest函數來結束請求。
// 7.關閉句柄,釋放緩存區資源。// PS:示例代碼:// 數據上傳
BOOL Http_Upload(char *pszUploadUrl, BYTE *pUploadData, DWORD dwUploadDataSize)
{// 變量(略)// 分解URLif (FALSE == Http_UrlCrack(pszUploadUrl, szScheme, szHostName, szUserName, szPassword, szUrlPath, szExtraInfo, MAX_PATH)){return FALSE;}// 數據上傳do {// 建立會話hInternet = ::InternetOpen("WinInet Http Upload v1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);if (NULL == hInternet){Http_ShowError("InternetOpen");break;}// 建立連接hConnect = ::InternetConnect(hInternet, szHostName, INTERNET_DEFAULT_HTTP_PORT, szUserName, szPassword, INTERNET_SERVICE_HTTP, 0, 0);if (NULL == hConnect){Http_ShowError("InternetConnect");break;}// 拼接szUrlPathif (0 < ::lstrlen(szExtraInfo)){::lstrcat(szUrlPath, szExtraInfo);}// 設置標記dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_COOKIES |INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD;// 創建POST請求hRequest = ::HttpOpenRequest(hConnect, "POST", szUrlPath, NULL, NULL, NULL, dwOpenRequestFlags, 0);if (NULL == hRequest){Http_ShowError("HttpOpenRequest");break;}// 發送請求,告訴服務器傳輸數據的總大小::RtlZeroMemory(&internetBuffers, sizeof(internetBuffers));internetBuffers.dwStructSize = sizeof(internetBuffers);internetBuffers.dwBufferTotal = dwPostDataSize;bRet = ::HttpSendRequestEx(hRequest, internetBuffers, NULL, 0, 0);if (FALSE == bRet){break;}// 發送數據bRet = ::InternetWriteFile(hRequest, pUploadData, dwUploadDataSize, &dwRet);if (FALSE == bRet){break;}// 發送完畢,結束請求bRet = ::HttpEndRequest(hRequest, NULL, 0, 0);if (FALSE == bRet){break;}// 接收響應報文信息頭pResponseHeaderInfo = new unsigned char[dwResponseHeaderInfoSize];if (NULL == pResponseHeaderInfo){break;}::RtlZeroMemory(pResponseHeaderInfo, dwResponseHeaderInfoSize);bRet = ::HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, pResponseHeaderInfo, &dwResponseHeaderInfoSize, NULL);if (FALSE == bRet){Http_ShowError("HttpQueryInfo");break;}// 從字段"Content-Length"中獲取數據長度bRet = Http_GetContentLength((char*)pResponseHeaderInfo, &dwResponseHeaderInfoSize);if (FALSE == bRet){break;}// 接收報文主體內容pBuf = new BYTE[dwBufSize];if (NULL = pBuf){break;}pResponseBodyData = new BYTE[dwResponseBodyDataSize];if (NULL == pResponseBodyData){break;}::RtlZeroMemory(pResponseBodyData, dwResponseBodyDataSize);do{::RtlZeroMemory(pBuf, dwBufSize);bRet = ::InternetReadFile(hRequest, pBuf, dwBufSize, &dwRet);if (FALSE == bRet){Http_ShowError("InternetReadFile");break;}::RtlCopyMemory((pResponseBodyData + dwOffset), pBuf, dwRet);dwOffset += dwRet;} while (dwResponseBodyDataSize > dwOffset);} while (FALSE);// 關閉并釋放(略)return bRet;
}// PS:基于WinInet庫的HTTP文件下載步驟:
// 1.調用InternetCrackUrl函數分解URL,從URL中提取網站的域名、資源路徑以及URL的附加信息等。
// 2.調用InternetOpen函數建立會話并獲取會話句柄。
// 3.調用InternetConnect函數建立連接,并指定連接的類型為INTERNET_SERVICE_HTTP,即連接到HTTP服務器上。
// 4.使用HttpOpenRequest創建一個GET請求,同時指明訪問服務器的資源路徑并設置HTTP的訪問標志。
// 5.使用HttpSendRequestEx函數將訪問請求發送到服務器上。這樣服務器就可以獲取請求信息和返回響應頭信息。
// 6.調用HttpQueryInfo函數獲取返回的Response Header信息,并根據Content-Length字段中的數據確定接收的數據長度,申請接收數據的緩存區。
// 7.循環調用InternetReadFile函數接收數據,直到接收數據的長度等于返回數據的長度。
// 8.關閉句柄,釋放數據緩存區。// PS:示例代碼:// 數據下載BOOL Http_Download(char* pszDownloadUrl, BYTE **ppDownloadData, DWORD *pdwDownloadDataSize)
{// 變量(略)// 分解URLif (FALSE == Http_UrlCrack(pszDownloadUrl, szScheme, szHostName, szUserName, szPassword, szUrlPath, szExtraInfo, MAX_PATH)){return FALSE;}// 拼接szUrlPathif (0 < ::lstrlen(szExtraInfo)){::lstrcat(szUrlPath, szExtraInfo);}// 數據下載do {// 建立會話hInternet = ::InternetOpen("WinInte Http Download v1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);if (NULL == hInternet){Http_ShowError("InternetOpen");break;}// 建立連接hConnect = ::InternetConnect(hInternet, szHostName, INTERNET_DEFAULT_HTTP_PORT, szUserName, szPassword, INTERNET_SERVICE_HTTP, 0, 0);if (NULL == hConnect){Http_ShowError("InternetConnect");break;}// 設置標志dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_COOKIES |INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD;// 創建請求hRequest = ::HttpOpenRequest(hConnect, "GET", szUrlPath, NULL, NULL, NULL, dwOpenRequestFlags, 0);if (NULL == hRequest){Http_ShowError("HttpOpenRequest");break;}// 發送請求bRet = ::HttpSendRequestEx(hRequest, NULL, 0, NULL, 0);if (FALSE == bRet){Http_ShowError("HttpSendRequestEx");break;}// 接收響應的報文信息頭pResponseHeaderInfo = new unsigned char[dwResponseHeaderInfoSize];if (NULL == pResponseHeaderInfo){break;}::RtlZeroMemory(pResponseHeaderInfo, dwResponseHeaderInfoSize);// 查詢響應信息頭bRet = ::HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, pResponseHeaderInfo, &dwResponseHeaderInfoSize);if (FALSE == bRet){Http_ShowError("HttpQueryInfo");break;}// 從字段"Content-Length"中獲取數據長度bRet = Http_GetContentLength((char*)pResponseHeaderInfo, dwResponseHeaderInfoSize);if (FALSE == bRet){break;}// 申請動態內存,用于接收報文主體數據pBuf = new BYTE[dwBufSize];if (NULL == pBuf){break;}::RtlZeroMemory(pDownloadData, dwDownloadDataSize);// 循環接收數據do {::RtlZeroMemory(pBuf, dwBufSize);bRet = ::InternetReadFile(hRequest, pBuf, dwBufSize, &dwRet);if (FALSE == bRet){break;}::RtlCopyMemory((PVOID)(pDownloadData + dwOffset), pBuf, dwRet);dwOffset += dwRet;} while (dwDownloadDataSize > dwOffset);// 返回數據**ppDownloadData = pDownloadData;*pdwDownloadDataSize = dwDownloadDataSize;} while (FALSE);// 關閉句柄,釋放緩存區(略)return bRet;
}
總結
以上是生活随笔為你收集整理的WinInet库之Http通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开学不容错过的蓝牙耳机,高品质蓝牙耳机排
- 下一篇: 建立内网Windows补丁服务器