C/C++實現(xiàn)發(fā)送與接收HTTP/S請求的示例代碼
前言
HTTP(Hypertext Transfer Protocol)是一種用于傳輸超文本的協(xié)議。它是一種無狀態(tài)的、應(yīng)用層的協(xié)議,用于在計算機之間傳輸超文本文檔,通常在 Web 瀏覽器和 Web 服務(wù)器之間進(jìn)行數(shù)據(jù)通信。HTTP 是由互聯(lián)網(wǎng)工程任務(wù)組(IETF)定義的,它是基于客戶端-服務(wù)器模型的協(xié)議,其中客戶端向服務(wù)器發(fā)送請求,服務(wù)器以相應(yīng)的數(shù)據(jù)作為響應(yīng)。HTTP 協(xié)議是建立在 TCP/IP 協(xié)議之上的,通常使用默認(rèn)的端口號80。
以下是 HTTP 的一些關(guān)鍵特點:
- 文本協(xié)議: HTTP 是一種文本協(xié)議,通過純文本的方式傳輸數(shù)據(jù)。這使得它易于閱讀和調(diào)試,但也帶來了一些安全性方面的問題,因此在需要更安全的通信時,通常會使用 HTTPS(HTTP Secure)來加密通信內(nèi)容。
- 無狀態(tài)協(xié)議: HTTP 是一種無狀態(tài)協(xié)議,意味著每個請求和響應(yīng)之間都是相互獨立的,服務(wù)器不會保存關(guān)于客戶端的任何狀態(tài)信息。這導(dǎo)致了一些問題,例如在進(jìn)行用戶身份驗證時,需要額外的機制來保持狀態(tài)。
- 請求方法: HTTP 定義了一組請求方法,其中最常見的包括 GET(獲取資源)、POST(提交數(shù)據(jù))、PUT(更新資源)、DELETE(刪除資源)等。這些方法指示了客戶端對服務(wù)器執(zhí)行的操作。
- 狀態(tài)碼: 服務(wù)器在響應(yīng)中返回一個狀態(tài)碼,用于表示請求的處理結(jié)果。常見的狀態(tài)碼包括200(OK,請求成功)、404(Not Found,未找到請求的資源)、500(Internal Server Error,服務(wù)器內(nèi)部錯誤)等。
- URL(Uniform Resource Locator): HTTP 使用 URL 來標(biāo)識和定位網(wǎng)絡(luò)上的資源。URL 包括協(xié)議部分(如 “http://”)、主機名(如 “www.xxx.com”)、路徑部分等。
- Header(報頭): HTTP 的請求和響應(yīng)中都包含頭部信息,用于傳遞關(guān)于消息的附加信息。頭部可以包含各種信息,如身份驗證信息、內(nèi)容類型、緩存控制等。
HTTP 是萬維網(wǎng)上數(shù)據(jù)通信的基礎(chǔ),它定義了客戶端和服務(wù)器之間的通信規(guī)范。它支持超文本(Hypertext),使得用戶能夠通過點擊鏈接訪問和瀏覽相關(guān)的文檔和資源,是構(gòu)建 Web 應(yīng)用程序的重要基礎(chǔ)之一。
Web路徑分割
如下提供的代碼片段包含了兩個用于分割URL的函數(shù):HttpUrlSplitA
和HttpUrlSplitB
。這些函數(shù)的目的是從給定的URL中提取主機名和路徑。下面是對兩個函數(shù)的概述:
HttpUrlSplitA
函數(shù):- 使用Windows API的
InternetCrackUrl
函數(shù),該函數(shù)專門用于解析URL。 - 通過
URL_COMPONENTS
結(jié)構(gòu)體來傳遞和接收URL的不同部分,包括主機名和路徑。 - 適用于對URL進(jìn)行標(biāo)準(zhǔn)化處理的情境,直接調(diào)用系統(tǒng)提供的功能。
- 使用Windows API的
HttpUrlSplitB
函數(shù):- 手動實現(xiàn)對URL的解析,通過檢查URL的開頭,然后手動提取主機名和路徑。
- 對URL進(jìn)行了一些基本的檢查,如是否以 “http://” 或 “https://” 開頭。
- 提供了一種更靈活的方式,但需要開發(fā)者自己處理解析邏輯。
總體而言,這兩個函數(shù)都屬于URL處理的一部分,但選擇使用哪個函數(shù)可能取決于具體的項目需求和開發(fā)者的偏好。HttpUrlSplitA
直接利用Windows API提供的功能,更為直觀。而HttpUrlSplitB
則通過手動解析,提供了更多的控制權(quán)。在實際項目中,選擇取決于開發(fā)者對項目的要求和對代碼控制的需求。
InternetCrackUrl
用于解析 URL。它將 URL 拆分為各個組成部分,例如協(xié)議、主機名、端口、路徑等。這個函數(shù)的目的是方便開發(fā)者處理 URL,以便更容易地獲取和使用其中的信息。
以下是關(guān)于 InternetCrackUrl
函數(shù)的一些關(guān)鍵信息:
BOOL InternetCrackUrl( _In_ PCTSTR lpszUrl, _In_ DWORD dwUrlLength, _In_ DWORD dwFlags, _Out_ LPURL_COMPONENTS lpUrlComponents );
lpszUrl
: 指向包含 URL 字符串的空終止字符串的指針。dwUrlLength
: URL 字符串的長度,如果是 NULL 終止字符串,可以設(shè)置為DWORD(-1)
。dwFlags
: 一組標(biāo)志,用于指定解析行為。lpUrlComponents
: 指向一個URL_COMPONENTS
結(jié)構(gòu)體的指針,該結(jié)構(gòu)體用于接收 URL 的各個組成部分。
URL_COMPONENTS
結(jié)構(gòu)體包括以下字段:
typedef struct _URL_COMPONENTS { DWORD dwStructSize; LPTSTR lpszScheme; DWORD dwSchemeLength; INTERNET_SCHEME nScheme; LPTSTR lpszHostName; DWORD dwHostNameLength; INTERNET_PORT nPort; LPTSTR lpszUserName; DWORD dwUserNameLength; LPTSTR lpszPassword; DWORD dwPasswordLength; LPTSTR lpszUrlPath; DWORD dwUrlPathLength; LPTSTR lpszExtraInfo; DWORD dwExtraInfoLength; } URL_COMPONENTS, *LPURL_COMPONENTS;
dwStructSize
: 結(jié)構(gòu)體大小。lpszScheme
: 指向字符串的指針,該字符串包含 URL 的方案部分(如 “http”)。nScheme
: 表示 URL 方案的整數(shù)值。lpszHostName
: 指向字符串的指針,包含主機名部分。nPort
: 表示端口號。lpszUserName
和lpszPassword
: 分別是用戶名和密碼的部分。lpszUrlPath
: URL 路徑部分。lpszExtraInfo
: 額外信息。
InternetCrackUrl
的返回值為 BOOL
類型,如果函數(shù)成功,返回非零值,否則返回零。函數(shù)成功后,lpUrlComponents
結(jié)構(gòu)體中的字段將被填充。
這個函數(shù)通常用于在網(wǎng)絡(luò)編程中處理 URL,例如在創(chuàng)建網(wǎng)絡(luò)請求時提取主機名、端口和路徑。
#define _CRT_SECURE_NO_WARNINGS #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <WinSock2.h> #include <Windows.h> #include <string> #include <WinInet.h> #pragma comment(lib, "WinInet.lib") #pragma comment(lib,"ws2_32") using namespace std; // 通過InternetCrackUrl函數(shù)實現(xiàn)切割 BOOL HttpUrlSplitA(const char* URL, LPSTR pszHostName, LPSTR pszUrlPath) { BOOL bRet = FALSE; URL_COMPONENTS url_info = { 0 }; RtlZeroMemory(&url_info, sizeof(url_info)); url_info.dwStructSize = sizeof(url_info); url_info.dwHostNameLength = MAX_PATH - 1; url_info.lpszHostName = pszHostName; url_info.dwUrlPathLength = MAX_PATH - 1; url_info.lpszUrlPath = pszUrlPath; bRet = InternetCrackUrl(URL, 0, 0, &url_info); if (FALSE == bRet) { return FALSE; } return TRUE; } int main(int argc, char* argv[]) { char szHostName[1024] = { 0 }; char szUrlPath[1024] = { 0 }; BOOL flag = HttpUrlSplitA("http://www.xxx.com/index.html", szHostName, szUrlPath); if (flag == TRUE) { printf("輸出主路徑:%s \n", szHostName); printf("輸出子路徑:%s \n", szUrlPath); } system("pause"); return 0; }
運行后則會對http://www.xxx.com/index.html
字符串進(jìn)行路徑切割,并輸出主目錄與子路徑,如下圖所示;
相對于使用原生API切割,自己實現(xiàn)也并不難,如下所示,通過_strnicmp
判斷字符串長度并切割特定的位置,實現(xiàn)對字符串的切割;
#define _CRT_SECURE_NO_WARNINGS #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <WinSock2.h> #include <Windows.h> #include <string> #include <WinInet.h> #pragma comment(lib, "WinInet.lib") #pragma comment(lib,"ws2_32") using namespace std; // 自己實現(xiàn)對URL路徑的拆分 bool HttpUrlSplitB(const char* pszUrl) { char szHost[256] = { 0 }; char* ptr = (char*)pszUrl; // 判斷開頭是否為http:// 或者 https:// 如果不是則返回-1 if (_strnicmp(ptr, "http://", 7) == 0) { ptr = ptr + 7; } else if (_strnicmp(ptr, "https://", 8) == 0) { ptr = ptr + 8; } else { return false; } int index = 0; while (index < 255 && *ptr && *ptr != '/') { szHost[index++] = *ptr++; } szHost[index] = '\0'; printf("主域名: %s \n 路徑: %s \n", szHost, ptr); return true; } int main(int argc, char* argv[]) { BOOL flag = HttpUrlSplitB("http://www.xxx.com/index.html"); system("pause"); return 0; }
實現(xiàn)HTTP訪問
HTTP 通常基于TCP(Transmission Control Protocol)。HTTP的本質(zhì)是建立在底層的Socket通信之上的一種應(yīng)用層協(xié)議。
概述HTTP訪問的過程:
- 建立TCP連接: HTTP通信首先需要建立TCP連接,通常默認(rèn)使用TCP的80端口。在建立連接之前,客戶端和服務(wù)器需要通過DNS解析獲取對應(yīng)的IP地址。
- 發(fā)送HTTP請求: 客戶端通過Socket向服務(wù)器發(fā)送HTTP請求,請求包括請求方法(GET、POST等)、URL路徑、HTTP協(xié)議版本等信息。同時,客戶端可以附帶一些請求頭(Headers)和請求體(Body),具體內(nèi)容根據(jù)請求的性質(zhì)而定。
- 服務(wù)器處理請求: 服務(wù)器接收到客戶端的HTTP請求后,根據(jù)請求的內(nèi)容進(jìn)行處理。處理的方式取決于請求的方法,例如GET請求用于獲取資源,POST請求用于提交數(shù)據(jù)等。服務(wù)器根據(jù)請求返回相應(yīng)的HTTP響應(yīng)。
- 發(fā)送HTTP響應(yīng): 服務(wù)器通過Socket向客戶端發(fā)送HTTP響應(yīng),響應(yīng)包括響應(yīng)狀態(tài)碼、響應(yīng)頭和響應(yīng)體。響應(yīng)狀態(tài)碼表示服務(wù)器對請求的處理結(jié)果,例如200表示成功,404表示未找到資源,500表示服務(wù)器內(nèi)部錯誤等。
- 關(guān)閉TCP連接: 一旦HTTP響應(yīng)發(fā)送完畢,服務(wù)器關(guān)閉與客戶端的TCP連接??蛻舳私邮胀觏憫?yīng)后也可以關(guān)閉連接,或者繼續(xù)發(fā)送其他請求。
整個HTTP訪問的本質(zhì)就是通過TCP連接在客戶端和服務(wù)器之間傳遞HTTP請求和響應(yīng)。Socket是負(fù)責(zé)實際數(shù)據(jù)傳輸?shù)牡讓訖C制,而HTTP協(xié)議則定義了在這個基礎(chǔ)上進(jìn)行通信的規(guī)范。這種分層的設(shè)計使得不同的應(yīng)用能夠使用同一個底層的網(wǎng)絡(luò)傳輸機制,提高了網(wǎng)絡(luò)通信的靈活性和可擴展性。
通常實現(xiàn)HTTP訪問與主機訪問相同,唯一的區(qū)別是主機應(yīng)用的訪問遵循的是服務(wù)端的封包規(guī)則,而對于Web來說則需要遵循HTTP特有的訪問規(guī)則,在Socket正式接收數(shù)據(jù)之前需要實現(xiàn)一個請求規(guī)范,也就是HTTP頭部。
HTTP頭部(HTTP headers)是HTTP請求和響應(yīng)中的重要組成部分,它們包含了與請求或響應(yīng)相關(guān)的信息。HTTP頭部的格式通常是一個名值對(key-value pair)的集合,每個頭部字段由一個字段名和一個字段值組成,它們以冒號分隔,例如:
HeaderName: HeaderValue
HTTP頭部通常以回車符(Carriage Return,\r
)和換行符(Line Feed,\n
)的組合(\r\n
)結(jié)束,每個頭部字段之間以\r\n
分隔。
以下是一些常見的HTTP頭部字段及其示例:
- 通用頭部(General Headers):
Cache-Control: no-cache
Date: Tue, 15 Nov 2022 08:12:31 GMT
Connection: keep-alive
- 請求頭部(Request Headers):
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
- 響應(yīng)頭部(Response Headers):
Content-Type: text/html; charset=utf-8
Content-Length: 12345
Server: Apache/2.4.41 (Unix)
- 實體頭部(Entity Headers):
Content-Encoding: gzip
Last-Modified: Wed, 20 Oct 2022 12:00:00 GMT
Etag: "5f0a3e51-20"
HTTP頭部的具體字段和含義可根據(jù)HTTP規(guī)范進(jìn)行擴展,不同的應(yīng)用場景和需求可能需要添加自定義的頭部字段。這些頭部字段在HTTP通信中起到了傳遞元信息、控制緩存、指定內(nèi)容類型等作用。在代碼中我們構(gòu)建了一個如下所示的頭部。
int ret = sprintf(context, "GET %s HTTP/1.1 \r\n" "Host: %s \r\n" "User-Agent: Mozilla/5.0 (Windows NT 10.0) LyShark HttpGet 1.0 \r\n" "Accept-Type: */* \r\n" "Connection: Close \r\n\r\n", szSubPath, szURL);
在這個HTTP GET請求的基本格式,它包含了一些必要的頭部信息。讓我們逐行解釋:
"GET %s HTTP/1.1 \r\n"
: 這表示使用HTTP協(xié)議的GET請求方式,%s
會被替換為實際的URL路徑,HTTP版本為1.1。"Host: %s \r\n"
: 這里設(shè)置了HTTP請求的Host
頭部,指定了服務(wù)器的主機名,%s
會被替換為實際的主機名。"User-Agent: Mozilla/5.0 (Windows NT 10.0) LyShark HttpGet 1.0 \r\n"
: 這是User-Agent
頭部,它標(biāo)識了發(fā)送請求的用戶代理(即瀏覽器或其他客戶端)。這里的字符串表示使用Mozilla瀏覽器5.0版本,運行在Windows NT 10.0操作系統(tǒng)上,LyShark HttpGet 1.0表示這個請求的自定義用戶代理。"Accept-Type: */* \r\n"
: 這是Accept-Type
頭部,表示客戶端可以接受任意類型的響應(yīng)內(nèi)容。"Connection: Close \r\n\r\n"
:Connection
頭部表示在完成請求后關(guān)閉連接,避免保持連接。\r\n\r\n
表示頭部結(jié)束,之后是可選的請求體。
綜合起來,這個HTTP GET請求的目的是獲取指定URL路徑的資源,請求頭部包含了一些必要的信息,例如主機名、用戶代理等。這是一個基本的HTTP請求格式,可以根據(jù)具體需求添加或修改頭部信息。
#define _CRT_SECURE_NO_WARNINGS #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <WinSock2.h> #include <Windows.h> #include <string> #include <WinInet.h> #pragma comment(lib, "WinInet.lib") #pragma comment(lib,"ws2_32") using namespace std; // 通過InternetCrackUrl函數(shù)實現(xiàn)切割 BOOL HttpUrlSplitA(const char* URL, LPSTR pszHostName, LPSTR pszUrlPath) { BOOL bRet = FALSE; URL_COMPONENTS url_info = { 0 }; RtlZeroMemory(&url_info, sizeof(url_info)); url_info.dwStructSize = sizeof(url_info); url_info.dwHostNameLength = MAX_PATH - 1; url_info.lpszHostName = pszHostName; url_info.dwUrlPathLength = MAX_PATH - 1; url_info.lpszUrlPath = pszUrlPath; bRet = InternetCrackUrl(URL, 0, 0, &url_info); if (FALSE == bRet) { return FALSE; } return TRUE; } // Get方式訪問頁面 char* Curl(const char* szURL, const char* szSubPath, const int port) { WSADATA wsaData; WSAStartup(0x0202, &wsaData); char* context = new char[1024 * 8]; int ret = sprintf(context, "GET %s HTTP/1.1 \r\n" "Host: %s \r\n" "User-Agent: Mozilla/5.0 (Windows NT 10.0) LyShark HttpGet 1.0 \r\n" "Accept-Type: */* \r\n" "Connection: Close \r\n\r\n", szSubPath, szURL); SOCKADDR_IN addr; SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); addr.sin_addr.S_un.S_addr = 0; addr.sin_port = htons(0); addr.sin_family = AF_INET; ret = bind(sock, (const sockaddr*)&addr, sizeof(SOCKADDR_IN)); hostent* local_addr = gethostbyname(szURL); if (local_addr) { ULONG ip = *(ULONG*)local_addr->h_addr_list[0]; addr.sin_addr.S_un.S_addr = ip; addr.sin_port = htons(port); ret = connect(sock, (const sockaddr*)&addr, sizeof(SOCKADDR_IN)); if (ret == NOERROR) { ret = send(sock, (const char*)context, (int)strlen(context), 0); do { ret = recv(sock, context, 8191, 0); if (ret <= 0) { break; } context[ret] = '\0'; printf("\n%s\n\n", context); } while (TRUE); } } closesocket(sock); WSACleanup(); return context; } // 訪問指定頁面 char* HttpGet(const char* szURL, const int port) { char master_url[1024] = { 0 }; char slave_url[1024] = { 0 }; char* curl_context = nullptr; // 將完整路徑切割為主路徑與次路徑 BOOL ref = HttpUrlSplitA(szURL, master_url, slave_url); if (TRUE == ref) { // 獲取所有網(wǎng)頁內(nèi)容 curl_context = Curl(master_url, slave_url, port); return curl_context; } return 0; } int main(int argc, char* argv[]) { char *szBuffer = HttpGet("http://www.lyshark.com/index.html", 80); // printf("%s \n", szBuffer); system("pause"); return 0; }
運行上述代碼則會自動請求http://www.lyshark.com/index.html
路徑的80
端口,以獲取返回參數(shù)信息,如下圖所示;
實現(xiàn)HTTPS訪問
HTTPS的訪問與HTTP基本類似,同樣是通過Socket訪問端口,同樣是發(fā)送特定的GET請求頭,唯一的不同在于當(dāng)鏈接被建立后,對于HTTPS來說多出一個TLS協(xié)商的過程,這是為了保護(hù)傳輸時的安全而增加的安全特定,為了能實現(xiàn)訪問我們需要使用OpenSSL庫對完成TLS的握手才行。
OpenSSL 是一個強大的開源軟件庫,提供了一系列的密碼學(xué)工具和庫函數(shù),廣泛用于網(wǎng)絡(luò)安全應(yīng)用的開發(fā)。它支持許多密碼學(xué)協(xié)議和算法,包括 SSL(Secure Sockets Layer)和 TLS(Transport Layer Security)協(xié)議,用于在計算機網(wǎng)絡(luò)上實現(xiàn)安全通信。
HTTPS握手過程是建立在TLS(Transport Layer Security)協(xié)議之上的。TLS是SSL(Secure Sockets Layer)的繼任者,用于在計算機網(wǎng)絡(luò)上保障通信安全。以下是HTTPS握手的基本流程:
- 客戶端Hello:
- 客戶端向服務(wù)器發(fā)送
ClientHello
消息,其中包含支持的TLS版本、支持的加密算法、支持的壓縮算法等信息。
- 客戶端向服務(wù)器發(fā)送
- 服務(wù)器Hello:
- 服務(wù)器從客戶端提供的信息中選擇一個合適的TLS版本和加密套件,并向客戶端發(fā)送
ServerHello
消息,同時發(fā)送服務(wù)器證書。
- 服務(wù)器從客戶端提供的信息中選擇一個合適的TLS版本和加密套件,并向客戶端發(fā)送
- 認(rèn)證:
- 客戶端驗證服務(wù)器發(fā)送的證書是否有效,通常包括證書的頒發(fā)機構(gòu)(CA)的簽名驗證。客戶端還可以驗證證書中包含的域名是否匹配正在連接的域名。
- 密鑰交換:
- 客戶端生成一個隨機值,使用服務(wù)器的公鑰加密該隨機值,然后將加密后的數(shù)據(jù)發(fā)送給服務(wù)器。服務(wù)器使用自己的私鑰解密,得到客戶端生成的隨機值。這兩個隨機值將用于生成對話密鑰。
- 對話密鑰的生成:
- 客戶端和服務(wù)器使用客戶端生成的隨機值、服務(wù)器生成的隨機值以及前面協(xié)商的算法,通過一系列協(xié)商步驟生成對話密鑰。
- 加密通信:
- 客戶端和服務(wù)器使用生成的對話密鑰對通信進(jìn)行加密和解密,確保數(shù)據(jù)的隱私和完整性。
整個握手過程確保了通信雙方的身份驗證、密鑰的安全協(xié)商以及通信內(nèi)容的保密性和完整性。握手完成后,客戶端和服務(wù)器使用協(xié)商得到的對話密鑰進(jìn)行加密通信,從而實現(xiàn)了安全的HTTPS連接。
如下所示代碼以演示訪問必應(yīng)為例,需要獲取必應(yīng)的IP地址,以及在GET請求中更改訪問域名為BING;
#define _CRT_SECURE_NO_WARNINGS #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <iostream> #include <WinSock2.h> #include <openssl/ssl.h> #pragma comment(lib,"ws2_32.lib") #pragma comment(lib,"libssl.lib") #pragma comment(lib,"libcrypto.lib") using namespace std; const wchar_t* GetWC(const char* c) { const size_t cSize = strlen(c) + 1; wchar_t* wc = new wchar_t[cSize]; mbstowcs(wc, c, cSize); return wc; } int main(int argc, char* argv[]) { WSADATA WSAData; SOCKET sock; struct sockaddr_in ClientAddr; if (WSAStartup(MAKEWORD(2, 0), &WSAData) != SOCKET_ERROR) { ClientAddr.sin_family = AF_INET; ClientAddr.sin_port = htons(443); ClientAddr.sin_addr.s_addr = inet_addr("202.89.233.101"); sock = socket(AF_INET, SOCK_STREAM, 0); int Ret = connect(sock, (LPSOCKADDR)&ClientAddr, sizeof(ClientAddr)); if (Ret == 0) { } } // 初始化OpenSSL庫 創(chuàng)建SSL會話環(huán)境等 SSL_CTX* pctxSSL = SSL_CTX_new(TLSv1_2_client_method()); if (pctxSSL == NULL) { return -1; } SSL* psslSSL = SSL_new(pctxSSL); if (psslSSL == NULL) { return -1; } SSL_set_fd(psslSSL, sock); INT iErrorConnect = SSL_connect(psslSSL); if (iErrorConnect < 0) { return -1; } std::wcout << "SLL ID: " << SSL_get_cipher(psslSSL) << std::endl; // 發(fā)包 std::string strWrite = "GET https://cn.bing.com/ HTTP/1.1\r\n" "Host: cn.bing.com\r\n" "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0 \r\n" "Accept-Type: */* \r\n" "Connection: close\r\n\r\n"; INT iErrorWrite = SSL_write(psslSSL, strWrite.c_str(), strWrite.length()) < 0; if (iErrorWrite < 0) { return -1; } // 收包并輸出 LPSTR lpszRead = new CHAR[8192]; INT iLength = 1; while (iLength >= 1) { iLength = SSL_read(psslSSL, lpszRead, 8192 - 1); if (iLength < 0) { std::wcout << "Error SSL_read" << std::endl; delete[] lpszRead; return -1; } lpszRead[iLength] = TEXT('\0'); std::wcout << GetWC(lpszRead); } delete[] lpszRead; closesocket(sock); WSACleanup(); system("pause"); return 0; }
成勛運行后將會對必應(yīng)發(fā)起https訪問,并獲取返回值信息,如下圖所示;
以上就是C/C++實現(xiàn)發(fā)送與接收HTTP/S請求的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于C/C++發(fā)送與接收HTTP/S請求的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于對話框程序中讓對話框捕獲WM_KEYDOWN消息的實現(xiàn)方法
下面我們將通過程序給大家演示基于對話框的應(yīng)用程序?qū)M_KEYDOWN消息的捕獲。需要的朋友可以參考下2013-05-05C++用read()和write()讀寫二進(jìn)制文件的超詳細(xì)教程
二進(jìn)制的文件肉眼我們是讀不懂的,如果通過二進(jìn)制的讀寫操作就可以讀懂,下面這篇文章主要給大家介紹了關(guān)于C++用read()和write()讀寫二進(jìn)制文件的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06