学懂C++(四十):网络编程——深入详解 HTTP、HTTPS 及基于 Windows 系统的 C++ 实现
目录
一、引言
二、HTTP 协议
1. HTTP 概述
2. HTTP 工作原理
3. HTTP 请求和响应格式
HTTP 请求格式
4. HTTP 状态码
三、HTTPS 协议
1. HTTPS 概述
2. HTTPS 工作原理
四、基于 Windows 系统的 C++ 实现
1. 准备工作
2. HTTP 客户端实现
示例代码
3. HTTPS 客户端实现
示例代码
4. HTTPS 服务器实现
示例代码
五、总结
一、引言
在现代互联网中,HTTP 和 HTTPS 是两种最常见的应用层协议,用于在客户端(如浏览器)和服务器之间传输数据。理解这两种协议的工作原理、区别及其在 C++ 中的实现,对于网络编程开发者来说至关重要。本文将深入解析 HTTP 和 HTTPS 的基础概念、工作原理及其在 Windows 环境下使用 C++ 进行实现的详细过程。
二、HTTP 协议
1. HTTP 概述
HTTP (Hypertext Transfer Protocol) 是一种应用层协议,用于分布式、协作式和超媒体信息系统。HTTP 是万维网的数据通信基础,主要特点包括:
- 无状态:每个 HTTP 请求都是独立的,服务器不保留请求间的状态。
- 简单灵活:易于实现和扩展,支持多种数据类型。
- 面向请求/响应模型:客户端发送请求,服务器返回响应。
2. HTTP 工作原理
HTTP 使用 TCP 作为传输层协议,遵循以下典型的请求/响应模型:
- 客户端与服务器建立 TCP 连接。
- 客户端发送 HTTP 请求,包含请求行、请求头和可选的请求体。
- 服务器处理请求并返回 HTTP 响应,包含状态行、响应头和可选的响应体。
- 关闭连接或保持连接,根据连接的设置(如
Connection: keep-alive)。
3. HTTP 请求和响应格式
HTTP 请求格式
请求行:方法 URL 版本
请求头:头部字段名: 值
空行
请求体(可选)
示例:
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
HTTP 响应格式
状态行:版本 状态码 状态消息
响应头:头部字段名: 值
空行
响应体(可选)
示例:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 123<html>...</html>
4. HTTP 状态码
HTTP 状态码表示服务器对请求的处理结果,常见的状态码包括:
- 1xx (信息):请求已接收,继续处理。
- 2xx (成功):请求成功,常见如
200 OK。 - 3xx (重定向):需要进一步操作以完成请求,常见如
301 Moved Permanently。 - 4xx (客户端错误):请求包含语法错误或无法完成,常见如
404 Not Found。 - 5xx (服务器错误):服务器在处理请求时发生错误,常见如
500 Internal Server Error。
三、HTTPS 协议
1. HTTPS 概述
HTTPS (Hypertext Transfer Protocol Secure) 是一种通过 SSL/TLS 协议进行加密的 HTTP 协议,用于在客户端和服务器之间建立安全的通信通道。HTTPS 增强了 HTTP 的安全性,主要特点包括:
- 加密:保护数据在传输过程中不被窃听。
- 身份验证:验证服务器身份,防止中间人攻击。
- 数据完整性:确保数据在传输过程中不被篡改。
2. HTTPS 工作原理
HTTPS 使用 SSL/TLS 协议对数据进行加密,典型的工作流程如下:
- 客户端发起 HTTPS 连接请求。
- 服务器返回 SSL/TLS 证书,包含服务器的公钥。
- 客户端验证证书的合法性,生成对称密钥,并使用服务器公钥加密该密钥。
- 服务器使用私钥解密密钥,建立加密通信通道。
- 客户端与服务器进行加密通信。
四、基于 Windows 系统的 C++ 实现
1. 准备工作
在 Windows 系统上使用 C++ 进行 HTTP 和 HTTPS 通信,可以使用 Windows API 或开源库(如 libcurl)。本文将使用 Windows API 进行示例演示。
2. HTTP 客户端实现
示例代码
#include <windows.h> // 包含 Windows API 函数和常量
#include <wininet.h> // 包含 Windows Internet 函数
#include <iostream> // 包含输入输出流
#pragma comment(lib, "wininet.lib") // 链接 wininet 库int main() {// 初始化 Internet 句柄HINTERNET hInternet = InternetOpen(L"MyHTTPClient", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);if (!hInternet) {std::cerr << "InternetOpen failed: " << GetLastError() << std::endl;return -1;}// 连接到指定的服务器HINTERNET hConnect = InternetConnect(hInternet, L"www.example.com", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);if (!hConnect) {std::cerr << "InternetConnect failed: " << GetLastError() << std::endl;InternetCloseHandle(hInternet);return -1;}// 创建一个 HTTP 请求句柄HINTERNET hRequest = HttpOpenRequest(hConnect, L"GET", L"/index.html", NULL, NULL, NULL, 0, 0);if (!hRequest) {std::cerr << "HttpOpenRequest failed: " << GetLastError() << std::endl;InternetCloseHandle(hConnect);InternetCloseHandle(hInternet);return -1;}// 发送 HTTP 请求if (!HttpSendRequest(hRequest, NULL, 0, NULL, 0)) {std::cerr << "HttpSendRequest failed: " << GetLastError() << std::endl;InternetCloseHandle(hRequest);InternetCloseHandle(hConnect);InternetCloseHandle(hInternet);return -1;}// 读取服务器响应的数据char buffer[4096];DWORD bytesRead;while (InternetReadFile(hRequest, buffer, sizeof(buffer) - 1, &bytesRead) && bytesRead) {buffer[bytesRead] = '\0'; // 添加字符串终止符std::cout << buffer; // 输出响应内容}// 关闭句柄InternetCloseHandle(hRequest);InternetCloseHandle(hConnect);InternetCloseHandle(hInternet);return 0;
}
解析:
- InternetOpen:初始化使用
wininet的应用程序。- InternetConnect:连接到指定的服务器。
- HttpOpenRequest:创建一个 HTTP 请求句柄。
- HttpSendRequest:发送 HTTP 请求。
- InternetReadFile:读取服务器响应的数据。
3. HTTPS 客户端实现
示例代码
#include <windows.h> // 包含 Windows API 函数和常量
#include <wininet.h> // 包含 Windows Internet 函数
#include <iostream> // 包含输入输出流
#pragma comment(lib, "wininet.lib") // 链接 wininet 库int main() {// 初始化 Internet 句柄HINTERNET hInternet = InternetOpen(L"MyHTTPSClient", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);if (!hInternet) {std::cerr << "InternetOpen failed: " << GetLastError() << std::endl;return -1;}// 连接到指定的 HTTPS 服务器HINTERNET hConnect = InternetConnect(hInternet, L"www.example.com", INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);if (!hConnect) {std::cerr << "InternetConnect failed: " << GetLastError() << std::endl;InternetCloseHandle(hInternet);return -1;}// 创建一个 HTTPS 请求句柄HINTERNET hRequest = HttpOpenRequest(hConnect, L"GET", L"/index.html", NULL, NULL, NULL, INTERNET_FLAG_SECURE, 0);if (!hRequest) {std::cerr << "HttpOpenRequest failed: " << GetLastError() << std::endl;InternetCloseHandle(hConnect);InternetCloseHandle(hInternet);return -1;}// 发送 HTTPS 请求if (!HttpSendRequest(hRequest, NULL, 0, NULL, 0)) {std::cerr << "HttpSendRequest failed: " << GetLastError() << std::endl;InternetCloseHandle(hRequest);InternetCloseHandle(hConnect);InternetCloseHandle(hInternet);return -1;}// 读取服务器响应的数据char buffer[4096];DWORD bytesRead;while (InternetReadFile(hRequest, buffer, sizeof(buffer) - 1, &bytesRead) && bytesRead) {buffer[bytesRead] = '\0'; // 添加字符串终止符std::cout << buffer; // 输出响应内容}// 关闭句柄InternetCloseHandle(hRequest);InternetCloseHandle(hConnect);InternetCloseHandle(hInternet);return 0;
}
解析: 与 HTTP 客户端的实现类似,主要区别在于:
- InternetConnect 中使用
INTERNET_DEFAULT_HTTPS_PORT。- HttpOpenRequest 中使用
INTERNET_FLAG_SECURE标志。
4. HTTPS 服务器实现
基于 Windows 的 C++ 实现 HTTPS 服务器相对复杂,通常建议使用开源库(如 OpenSSL)来处理 SSL/TLS 加密。以下是一个简单的 HTTPS 服务器示例,使用 OpenSSL 进行 SSL/TLS 加密。
示例代码
#include <iostream> // 包含输入输出流
#include <openssl/ssl.h> // 包含 OpenSSL 函数和常量
#include <openssl/err.h> // 包含 OpenSSL 错误处理函数
#include <unistd.h> // 包含 POSIX 操作系统 API
#include <netinet/in.h> // 包含网络库
#include <arpa/inet.h> // 包含网络库#define PORT 8080
#define CERT_FILE "server.crt" // 证书文件路径
#define KEY_FILE "server.key" // 密钥文件路径// 初始化 OpenSSL 库
void init_openssl() {SSL_load_error_strings(); // 加载错误字符串OpenSSL_add_ssl_algorithms(); // 加载加密算法
}// 清理 OpenSSL 库
void cleanup_openssl() {EVP_cleanup(); // 清理加密算法
}// 创建 SSL 上下文
SSL_CTX* create_context() {const SSL_METHOD *method;SSL_CTX *ctx;method = SSLv23_server_method(); // 创建服务器方法ctx = SSL_CTX_new(method); // 创建新 SSL 上下文if (!ctx) {perror("Unable to create SSL context");ERR_print_errors_fp(stderr);exit(EXIT_FAILURE);}return ctx;
}// 配置 SSL 上下文,加载证书和私钥
void configure_context(SSL_CTX *ctx) {SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM); // 加载证书文件SSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, SSL_FILETYPE_PEM); // 加载私钥文件
}int main() {int sockfd;struct sockaddr_in addr;init_openssl(); // 初始化 OpenSSLSSL_CTX *ctx = create_context(); // 创建 SSL 上下文configure_context(ctx); // 配置 SSL 上下文sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字if (sockfd < 0) {perror("Unable to create socket");exit(EXIT_FAILURE);}addr.sin_family = AF_INET;addr.sin_port = htons(PORT);addr.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { // 绑定套接字perror("Unable to bind");exit(EXIT_FAILURE);}if (listen(sockfd, 1) < 0) { // 监听连接perror("Unable to listen");exit(EXIT_FAILURE);}while (1) {struct sockaddr_in addr;uint len = sizeof(addr);SSL *ssl;int client = accept(sockfd, (struct sockaddr*)&addr, &len); // 接受客户端连接if (client < 0) {perror("Unable to accept");exit(EXIT_FAILURE);}ssl = SSL_new(ctx); // 创建新 SSL 结构SSL_set_fd(ssl, client); // 关联 SSL 结构和客户端套接字if (SSL_accept(ssl) <= 0) { // SSL 握手ERR_print_errors_fp(stderr);} else {const char reply[] = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello, HTTPS!";SSL_write(ssl, reply, strlen(reply)); // 发送响应}SSL_shutdown(ssl); // 关闭 SSL 连接SSL_free(ssl); // 释放 SSL 结构close(client); // 关闭客户端套接字}close(sockfd); // 关闭服务器套接字SSL_CTX_free(ctx); // 释放 SSL 上下文cleanup_openssl(); // 清理 OpenSSLreturn 0;
}
解析:
- init_openssl:初始化 OpenSSL 库。
- create_context:创建 SSL 上下文。
- configure_context:配置 SSL 上下文,加载证书和私钥。
- socket、bind、listen:创建、绑定和监听套接字。
- accept:接受客户端连接,使用 SSL 处理加密通信。
五、总结
本文深入解析了 HTTP 和 HTTPS 的基础概念、工作原理及其在 Windows 系统下使用 C++ 进行实现的方法。通过详细的示例代码和解析,展示了如何使用 Windows API 和 OpenSSL 库实现 HTTP 和 HTTPS 客户端及服务器。希望本文能帮助读者更好地理解和掌握 HTTP、HTTPS 及其在 C++ 中的实现,提高网络编程技能。
相关文章:
学懂C++(四十):网络编程——深入详解 HTTP、HTTPS 及基于 Windows 系统的 C++ 实现
目录 一、引言 二、HTTP 协议 1. HTTP 概述 2. HTTP 工作原理 3. HTTP 请求和响应格式 HTTP 请求格式 4. HTTP 状态码 三、HTTPS 协议 1. HTTPS 概述 2. HTTPS 工作原理 四、基于 Windows 系统的 C 实现 1. 准备工作 2. HTTP 客户端实现 示例代码 3. HTTPS 客户…...
Element-06.案例
一.目标 实现下面这个页面,表格中的数据使用axois异步加载数据 二.实现步骤 首先在vue项目的views文件夹中新建一个tlias文件夹,用来存储该案例的相关组件。员工页面组件(EmpView.vue)和部门页面组件(DeptView.vue&…...
Axure高端交互元件库:助力产品与设计
用户体验(UX)和用户界面(UI)设计对于任何产品的成功都至关重要。为了在这个竞争激烈的市场中脱颖而出,设计师和产品开发团队需要依赖强大的工具来创造引人注目且功能丰富的交互界面。下面介绍一款Axure精心制作的"…...
后端开发刷题 | 二叉树的前序遍历
描述 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 数据范围:二叉树的节点数量满足 1≤n≤100 ,二叉树节点的值满足 1≤val≤100,树的各节点的值各不相同 示例 1: 示例1 输入: {1,#,2,3} 返…...
自动化之响应式Web设计:纯HTML和CSS的实现技巧
大家好,我是程序员小羊! 前言 响应式Web设计是一种使Web页面在各种设备和屏幕尺寸下都能良好显示的设计方法。随着移动设备的普及,响应式设计已经成为Web开发中的标准实践。本文将探讨如何使用纯HTML和CSS实现响应式Web设计,覆…...
SolarMarker 正在使用水坑攻击与伪造的 Chrome 浏览器更新进行攻击
在过去的三个月里,eSentire 的安全研究团队发现信息窃密恶意软件 SolarMarker 都没有发动攻击,却在最近忽然重返舞台。此前,SolarMarker 的运营者使用 SEO 投毒或者垃圾邮件来引诱受害者,受害者试图下载一些文档的免费模板&#x…...
uView的u-notice-bar组件横向滚动不生效问题解决
uView的u-notice-bar组件横向滚动不生效问题解决 此问题导致我换了vant组件的 notice-bar,一度以为是该组件存在bug。uniapp中有vant组件打包小程序又是一个问题,于是乎不得不回来继续折腾uView的u-notice-bar组件,偶然发现css属性animation-…...
基于免疫算法的最优物流仓储点选址方案MATLAB仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于免疫算法的最优物流仓储点选址方案MATLAB仿真。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运行 (完整程序运行后无水印) 3…...
基于Java爬取微博数据(三) 微博主页用户数据
基于Java爬取微博数据三 微博主页用户数据 数据分析爬取数据注意点 上一篇文章简单讲述了基于Java爬取微博数据(二),那么这篇将讲述如何基于 Java 爬取微博主页用户数据,下面开始具体的操作。 数据分析 在开始爬取微博主页用户数据之前,我们…...
Openstack 与 Ceph集群搭建(中): Ceph部署
文章目录 一、部署前说明1. ceph 版本选择依据2. ceph网络要求3. 硬件要求 二、部署架构三、部署过程1. 通用步骤2. 部署管理节点创建账号安装Cephadm运行bootstrap 3. 登录Ceph web4. 将其他节点加入集群同步ceph key安装ceph CLI命令行添加主机节点到集群添加OSD节点将监控节…...
上市公司上下游、客户数据匹配数据集(2001-2023年)
参考《中国工业经济》中陶锋(2023)的做法,对上市公司的上下游供应商和客户数据进行匹配。形成“上游供应商—目标企业—下游客户一年度数据集” 一、数据介绍 数据名称:上市公司-上下游和客户数据匹配 数据范围:上市…...
Promise 对象
Promise 对象是 JavaScript 中用于处理异步操作的一种机制。它代表了一个最终可能完成(fulfilled)或失败(rejected)的异步操作及其结果值。Promise 对象使得异步代码更加容易编写、理解和维护,因为它提供了一种链式调用…...
扫码头测试检测适配步骤
需求分析:适配扫码头看是否能正常工作即适配其能否调用相应的节点其能点亮扫码头并进一步获取其扫码的值。 1.首先先检验其串口是否正常通讯。 2.检验扫码头是否正常工作。 3.上电后拉高是否正常操作触发脚拉高其扫码头有无正常点亮。 4.按侧边键是否正常点亮扫…...
解决k8s分布式集群,子节点加入到主节点失败的问题
1.问题情况 Master主节点在 使用 kubeadm init 成功进行初始化后,如下所示 Your Kubernetes control-plane has initialized successfully!To start using your cluster, you need to run the following as a regular user:mkdir -p $HOME/.kubesudo cp -i /etc/k…...
什么是XSS跨站攻击?如何防护?
什么是XSS跨站攻击?如何防护? 什么是XSS攻击 XSS攻击,即跨站脚本攻击(Cross-Site Scripting),是一种常见的网络安全威胁。其本质是通过在网页中注入恶意的脚本代码,当其他用户浏览这些网页时&…...
谷粒商城实战笔记-问题记录-首页没有显示用户名-跨域session问题
文章目录 一,首页无用户信息二,定位三,两个问题1,跨域名session共享 一,首页无用户信息 谷粒商城首页,点击超链接您好,请登录,正常情况下应该跳转到Auth模块的login页面,…...
【面试宝典】redis常见面试题总结(上)
一、为什么使用 redis? 使用缓存的目的就是提升读写性能。为了提高读写性能,带来更高的并发量。减少对 MySQL 的请求量。 二、redis 有哪些好处? 读写速度快,因为数据存储在内存中,所以数据获取快。支持多种数据结构…...
数据仓库: 3- ETL过程
目录 3- ETL过程3.1 数据抽取(Extract)3.1.1 数据抽取的挑战3.1.2 数据抽取的方式3.1.2.1 全量抽取3.1.2.2 增量抽取3.1.2.3 实时抽取 3.1.3 数据抽取的技术3.1.4 数据抽取工具3.1.5 总结 3.2 数据转换(Transform)3.2.1 定义3.2.2…...
js数组变字符串
let array [1,2,3]; let string array.join(,); // 使用空格作为分隔符 console.log(string); // 输出: "1,2,3"...
日常问题笔记1
th:insert:将被引用的模板片段插⼊到自己的标签体中 th:replace:将被引用的模板片段替换掉自己 th:include:类似于 th:insert,⽽不是插⼊⽚段,它只插⼊此⽚段的内容 <!--1、比如抽取的公用代码片段如下--> <…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
