超详细讲解:TCP / UDP / HTTP / HTTPS 四种常见协议

超详细讲解:TCP / UDP / HTTP / HTTPS 四种常见协议

无论你是浏览网页、登录系统,还是打游戏、看视频,底层都绕不开两个关键的传输协议 —— TCP 和 UDP,以及两个应用层的明星 —— HTTP 和 HTTPS。本篇博客将带你系统梳理这四种常见协议的原理与差异,从底层传输到高层通信,从性能对比到安全机制,帮助你全面理解它们在实际开发与网络架构中的角色与选择依据。

1️⃣ TCP:稳定可靠的“快递包裹”

TCP(Transmission Control Protocol,传输控制协议)是一种在计算机网络中使用的面向连接的、可靠的传输层通信协议,在互联网中起着至关重要的作用,为应用层提供了稳定的数据传输服务。

面向连接:在开始传输数据之前,通信双方需要通过 “三次握手” 建立起一条可靠的连接通道。这就好比打电话,双方要先拨通电话,确认对方在线且可以正常交流后,才开始正式交谈。建立连接后,双方会维护连接状态,直到数据传输结束并通过 “四次挥手” 关闭连接。

可靠传输:TCP 使用了多种机制来确保数据能够准确无误地到达接收端。例如,通过序列号对每个数据段进行编号,接收端可以根据序列号来判断数据是否缺失或重复;采用确认应答机制,接收端收到数据后会向发送端发送确认信息,发送端只有在收到确认后才会认为数据已成功传输,否则会进行重传。

流量控制:为了防止发送方发送数据过快,导致接收方来不及处理而丢失数据,TCP 实现了流量控制功能。接收方会在确认报文中告知发送方自己当前的接收窗口大小,发送方根据这个窗口大小来调整发送数据的速率。

拥塞控制:当网络出现拥塞时,TCP 能够自动调整发送数据的速率,以缓解网络拥塞。常见的拥塞控制算法有慢开始、拥塞避免、快重传和快恢复等。

字节流服务:TCP 将应用层的数据看作是无结构的字节流,它不关心应用层数据的具体含义和结构,只是按照顺序将数据可靠地传输到对方。

1.2 代码示例

Tcp服务器(Server):

// tcp_server.cpp

#include

#include

#include

#ifdef _WIN32

#include

#pragma comment(lib,"ws2_32.lib")

#else

#include

#include

#endif

int main() {

#ifdef _WIN32

WSADATA wsaData;

WSAStartup(MAKEWORD(2,2), &wsaData);

#endif

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

if (server_fd == -1) {

std::cerr << "Socket creation failed\n";

return -1;

}

sockaddr_in server_addr{};

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(8888); // 监听端口

server_addr.sin_addr.s_addr = INADDR_ANY;

if (bind(server_fd, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) {

std::cerr << "Bind failed\n";

return -1;

}

listen(server_fd, 5);

std::cout << "Server listening on port 8888...\n";

sockaddr_in client_addr{};

socklen_t client_len = sizeof(client_addr);

int client_fd = accept(server_fd, (sockaddr*)&client_addr, &client_len);

if (client_fd >= 0) {

char buffer[1024] = {0};

int len = recv(client_fd, buffer, sizeof(buffer), 0);

std::cout << "Received from client: " << std::string(buffer, len) << "\n";

std::string reply = "Hello from server";

send(client_fd, reply.c_str(), reply.size(), 0);

}

#ifdef _WIN32

closesocket(client_fd);

WSACleanup();

#else

close(client_fd);

#endif

return 0;

}

Tcp客户端(Client):

// tcp_client.cpp

#include

#include

#include

#ifdef _WIN32

#include

#pragma comment(lib,"ws2_32.lib")

#else

#include

#include

#endif

int main() {

#ifdef _WIN32

WSADATA wsaData;

WSAStartup(MAKEWORD(2,2), &wsaData);

#endif

int sock_fd = socket(AF_INET, SOCK_STREAM, 0);

if (sock_fd < 0) {

std::cerr << "Socket creation failed\n";

return -1;

}

sockaddr_in server_addr{};

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(8888);

inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);

if (connect(sock_fd, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) {

std::cerr << "Connection failed\n";

return -1;

}

std::string message = "Hello from client";

send(sock_fd, message.c_str(), message.size(), 0);

char buffer[1024] = {0};

int len = recv(sock_fd, buffer, sizeof(buffer), 0);

std::cout << "Received from server: " << std::string(buffer, len) << "\n";

#ifdef _WIN32

closesocket(sock_fd);

WSACleanup();

#else

close(sock_fd);

#endif

return 0;

}

(Server)

💡 核心流程(5步):

创建套接字:socket()

绑定地址和端口:bind()

监听连接请求:listen()

接受客户端连接:accept()

读写数据通信:recv() / send()

可选第6步:关闭连接 close()(或 closesocket() on Windows)

(Client)

💡 核心流程(3步):

创建套接字:socket()

连接服务器:connect()

读写数据通信:send() / recv()

1.3进阶技巧(开发实战建议)

✅ 服务端建议:

多线程/线程池:每个客户端一个线程,或使用线程池处理任务(如 Boost.Asio)。

select()/epoll():高并发场景推荐使用,避免线程爆炸。

设置 SO_REUSEADDR:防止重启服务器时 “地址已被占用”。

int opt = 1;

setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

封装连接类:将 read() / write() 封装成类函数,提升可读性与可维护性。

✅ 客户端建议:

重连机制:连接失败时加入重试机制。

超时控制:使用 setsockopt() 设置连接和读写超时。

自动心跳包:长连接建议定时发送心跳,保持活跃。

✅ 通用建议:

使用 std::string / std::vector 管理数据缓冲区

对于跨平台开发,建议封装 socket 操作类,统一接口

日志调试非常重要,推荐用 spdlog 或 log4cpp 等库

2️⃣ UDP:快速轻量的“明信片”

UDP(User Datagram Protocol,用户数据报协议)是一种在传输层工作的通信协议,与 TCP(传输控制协议) 同属传输层,在网络通信中发挥着重要作用。

发送端将应用层要发送的数据加上 UDP 首部(包含源端口号、目的端口号、长度、校验和等字段),封装成 UDP 报文,然后通过网络层将报文发送出去。接收端收到 UDP 报文后,根据首部中的目的端口号将数据交付给相应的应用程序。如果校验和检查发现报文在传输过程中出现错误,UDP 会直接丢弃该报文,不会采取重传等补救措施。

无连接:UDP 在发送数据之前不需要像 TCP 那样通过三次握手建立连接。发送端直接将数据封装成 UDP 报文并发送出去,接收端收到报文后也无需进行专门的连接确认。这使得 UDP 的通信过程更加简单、快捷,就像发送明信片,不需要提前和对方打招呼确认能否接收,直接寄出即可。

不可靠传输:UDP 没有确认应答、重传等机制来保证数据一定能到达接收端,也不能保证数据的顺序和完整性。如果在传输过程中数据丢失或出错,UDP 不会自动处理,需要应用层自行解决。不过,在一些对实时性要求高、允许少量数据丢失的场景中,这种特性反而不会因为等待确认和重传而增加延迟。

面向数据报:UDP 以数据报为单位进行数据传输,每个 UDP 报文都包含完整的源端口、目的端口、数据等信息,发送端发送的每个数据报都是相互独立的,接收端接收数据报的顺序可能与发送端发送的顺序不一致。

高效率:由于没有复杂的连接建立、流量控制、拥塞控制等机制,UDP 的传输效率相对较高,开销较小,适合对传输效率要求高,能容忍一定数据丢失的应用场景。

支持广播和多播:UDP 允许发送端将数据报发送给网络中的所有主机(广播),或者发送给一组特定的主机(多播),而 TCP 只能进行一对一的通信 。

2.2 代码示例

Udp服务器(Server):

// udp_server.cpp

#include

#include

#include

#include

int main() {

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

if (sockfd < 0) {

std::cerr << "socket creation failed\n";

return -1;

}

sockaddr_in servaddr{};

servaddr.sin_family = AF_INET;

servaddr.sin_addr.s_addr = INADDR_ANY;

servaddr.sin_port = htons(8888);

if (bind(sockfd, (const sockaddr*)&servaddr, sizeof(servaddr)) < 0) {

std::cerr << "bind failed\n";

return -1;

}

char buffer[1024];

sockaddr_in cliaddr{};

socklen_t len = sizeof(cliaddr);

std::cout << "UDP Server listening on port 8888...\n";

while (true) {

int n = recvfrom(sockfd, buffer, sizeof(buffer)-1, 0, (sockaddr*)&cliaddr, &len);

if (n > 0) {

buffer[n] = '\0';

std::cout << "Received from client: " << buffer << "\n";

std::string reply = "Hello from UDP Server";

sendto(sockfd, reply.c_str(), reply.size(), 0, (sockaddr*)&cliaddr, len);

}

}

close(sockfd);

return 0;

}

Udp客户端(Client):

// udp_client.cpp

#include

#include

#include

#include

int main() {

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

if (sockfd < 0) {

std::cerr << "socket creation failed\n";

return -1;

}

sockaddr_in servaddr{};

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(8888);

inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

std::string msg = "Hello from UDP Client";

sendto(sockfd, msg.c_str(), msg.size(), 0, (const sockaddr*)&servaddr, sizeof(servaddr));

std::cout << "Sent to server: " << msg << "\n";

char buffer[1024];

socklen_t len = sizeof(servaddr);

int n = recvfrom(sockfd, buffer, sizeof(buffer)-1, 0, (sockaddr*)&servaddr, &len);

if (n > 0) {

buffer[n] = '\0';

std::cout << "Received from server: " << buffer << "\n";

}

close(sockfd);

return 0;

}

⚠️ 注意事项

✅ UDP 是无连接的

不需要 listen() 和 accept(),直接 sendto / recvfrom 就可以。

✅ 数据包大小限制

一般单个 UDP 报文 ≤ 64KB,建议小于 MTU(通常 1500 字节)。

✅ 无可靠性保证

丢包、乱序需要上层自己处理。

✅ 适合广播/多播

可通过 setsockopt() 配置广播、多播。

2.3 进阶技巧 (开发实战建议)

1️⃣ 使用 非阻塞套接字 + select()/epoll() 提高并发性能

UDP 不需要连接,但 recvfrom() 默认是阻塞的,建议:

fcntl(sockfd, F_SETFL, O_NONBLOCK); // 设置非阻塞

结合 select()/poll()/epoll() 实现事件驱动,提升响应效率。

2️⃣ 自定义协议实现“伪可靠”机制(如 ACK/重发)

因为 UDP 本身不可靠,在重要数据传输中可自建机制:

每个包加序号 seq_id

接收端回 ACK

超时未收到 ACK,重发

适用于低延迟、高可靠需求,如在线对战游戏、控制信号。

3️⃣ 使用 多线程 / 线程池 提高吞吐量

虽然 UDP 不涉及连接,但高并发数据接收与处理仍推荐多线程:

主线程接收数据

投递给工作线程池处理(解析 / 响应 / 落库等)

4️⃣ 支持 广播 / 多播,实现局域网自动发现

int yes = 1;

setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));

配合 255.255.255.255 或多播地址如 224.0.0.1,实现设备发现、状态同步。

5️⃣ 控制缓冲区大小,防止数据丢失

默认 UDP 缓冲区较小,推荐调大:

int size = 4 * 1024 * 1024;

setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));

否则在高并发场景下可能出现 recvfrom() 丢包。

6️⃣ 使用 connect() 优化性能(非必须)

虽然 UDP 是无连接的,也可以调用 connect() 绑定默认目标地址:

connect(sockfd, (sockaddr*)&dest, sizeof(dest));

send(sockfd, buf, len, 0); // 替代 sendto()

这样内核可以省略每次地址验证,提升性能。

7️⃣ 使用 MSG_PEEK 预读数据头部或快速丢包

recvfrom(sockfd, buf, sizeof(buf), MSG_PEEK, ...);

可用于查看包长度、来源 IP,做过滤处理后再正式读取。

8️⃣ 用 CRC32 / HMAC 校验数据完整性

UDP 没有校验机制,容易被篡改或传输错误,建议自行加上:

CRC32 校验(轻量)

HMAC-SHA256(安全通信)

3️⃣ HTTP:网页通信的标准语言

HTTP(Hypertext Transfer Protocol,超文本传输协议)是互联网上应用最广泛的客户端 - 服务器协议,用于传输超文本(如 HTML、图片、视频等)。它基于 TCP/IP 协议栈,是万维网(WWW)的核心协议。

无状态:

服务器不保存客户端的历史请求信息,每次请求都是独立的。这一特性简化了服务器设计,但也导致需要通过 Cookie、Session 等机制维护状态(如登录状态)。

请求 - 响应模式:

由客户端(如浏览器、APP)主动发起请求,服务器接收后返回响应,是典型的 “一问一答” 模式。

可扩展:

通过自定义请求头(Header)和响应头,支持功能扩展(如缓存控制、跨域资源共享 CORS)。

媒体无关:

可传输任意类型的数据(文本、图片、音频等),通过Content-Type头指定数据格式(如text/html、image/jpeg)。

3.2 代码示例:

以浏览器访问网页为例,HTTP 的完整交互流程如下:

建立 TCP 连接:客户端通过 TCP 与服务器的 80 端口(默认 HTTP 端口)建立连接(三次握手)。

发送 HTTP 请求:客户端向服务器发送请求报文(如获取某个网页)。

服务器处理请求:服务器解析请求,处理业务逻辑(如查询数据库)。

返回 HTTP 响应:服务器将处理结果封装为响应报文,返回给客户端。

关闭 TCP 连接:若为短连接,数据传输完成后断开连接(四次挥手);若为长连接,连接可复用。

Http服务器(Server):

#include

#include

#include

#include

#include

int main() {

// 创建 socket

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

if (server_fd < 0) {

std::cerr << "Socket creation failed\n";

return -1;

}

// 设置地址可重用

int opt = 1;

setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

// 设置服务器地址

sockaddr_in server_addr{};

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = INADDR_ANY;

server_addr.sin_port = htons(8080);

// 绑定地址

if (bind(server_fd, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) {

std::cerr << "Bind failed\n";

return -1;

}

// 监听连接

if (listen(server_fd, 5) < 0) {

std::cerr << "Listen failed\n";

return -1;

}

std::cout << "HTTP server running on http://localhost:8080\n";

while (true) {

// 接受客户端连接

sockaddr_in client_addr{};

socklen_t client_len = sizeof(client_addr);

int client_fd = accept(server_fd, (sockaddr*)&client_addr, &client_len);

if (client_fd < 0) {

std::cerr << "Accept failed\n";

continue;

}

// 接收客户端请求

char buffer[2048] = {0};

recv(client_fd, buffer, sizeof(buffer) - 1, 0);

std::cout << "Received request:\n" << buffer << "\n";

// 构造 HTTP 响应

std::string response =

"HTTP/1.1 200 OK\r\n"

"Content-Type: text/html\r\n"

"Connection: close\r\n"

"\r\n"

""

""

"C++ HTTP Server"

"

Hello from C++ HTTP Server!

"

"";

// 发送响应

send(client_fd, response.c_str(), response.size(), 0);

// 关闭客户端连接

close(client_fd);

}

// 关闭服务器 socket

close(server_fd);

return 0;

}

Http客户端(Client):

#include

#include

#include

#include

#include

int main() {

// 创建 socket

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

if (server_fd < 0) {

std::cerr << "Socket creation failed\n";

return -1;

}

// 设置地址可重用

int opt = 1;

setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

// 设置服务器地址

sockaddr_in server_addr{};

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = INADDR_ANY;

server_addr.sin_port = htons(8080);

// 绑定地址

if (bind(server_fd, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) {

std::cerr << "Bind failed\n";

return -1;

}

// 监听连接

if (listen(server_fd, 5) < 0) {

std::cerr << "Listen failed\n";

return -1;

}

std::cout << "HTTP server running on http://localhost:8080\n";

while (true) {

// 接受客户端连接

sockaddr_in client_addr{};

socklen_t client_len = sizeof(client_addr);

int client_fd = accept(server_fd, (sockaddr*)&client_addr, &client_len);

if (client_fd < 0) {

std::cerr << "Accept failed\n";

continue;

}

// 接收客户端请求

char buffer[2048] = {0};

recv(client_fd, buffer, sizeof(buffer) - 1, 0);

std::cout << "Received request:\n" << buffer << "\n";

// 构造 HTTP 响应

std::string response =

"HTTP/1.1 200 OK\r\n"

"Content-Type: text/html\r\n"

"Connection: close\r\n"

"\r\n"

""

""

"C++ HTTP Server"

"

Hello from C++ HTTP Server!

"

"";

// 发送响应

send(client_fd, response.c_str(), response.size(), 0);

// 关闭客户端连接

close(client_fd);

}

// 关闭服务器 socket

close(server_fd);

return 0;

}

注意事项

单线程处理:此示例为单线程,实际生产环境建议使用多线程或事件驱动(如 epoll)处理并发。跨平台:Windows 下需包含 并调用 WSAStartup() 初始化。请求解析:当前仅处理简单 GET 请求,复杂场景需解析 HTTP 请求头和方法。SO_REUSEADDR:设置地址可重用,避免端口占用问题。

3.3进阶技巧

多线程/异步:使用线程池或 select/epoll 支持多客户端并发。

支持 POST/JSON:解析请求体,处理复杂数据格式。

HTTPS 支持:集成 OpenSSL 或使用库如 cpp-httplib。

推荐库:cpp-httplib(轻量单文件)、Boost.Beast(功能强大)。

4️⃣ HTTPS:加密版 HTTP,安全通信之选

HTTPS(HTTP Secure)是 HTTP 协议的安全版本,通过TLS/SSL 加密和身份验证解决了 HTTP 明文传输的安全隐患。

1. 加密机制

HTTPS 通过对称加密和非对称加密结合实现安全通信:

非对称加密(TLS 握手阶段):

客户端与服务器交换公钥。

用服务器公钥加密生成的会话密钥(对称密钥)。

对称加密(数据传输阶段):

使用会话密钥加密 / 解密 HTTP 数据,效率更高。

2. 身份验证

数字证书:服务器通过 CA(证书颁发机构)签发的证书证明自己的身份。

证书链验证:客户端验证服务器证书的合法性(签名、有效期、域名匹配等)。

3. TLS 握手流程

客户端 Hello:发送支持的 TLS 版本、加密算法等。

服务器 Hello:选择 TLS 版本和加密算法,发送证书。

证书验证:客户端验证证书有效性。

密钥交换:客户端生成会话密钥,用服务器公钥加密后发送。

握手完成:双方使用会话密钥开始加密通信。

4.2 代码示例

Https 服务器(Server):

#include

#include

#include

#include

#include

#include

#include

void init_openssl() {

SSL_load_error_strings();

OpenSSL_add_ssl_algorithms();

}

void cleanup_openssl() {

EVP_cleanup();

}

int main() {

// 初始化 OpenSSL

init_openssl();

SSL_CTX* ctx = SSL_CTX_new(TLS_server_method());

if (!ctx) {

std::cerr << "SSL_CTX_new failed\n";

return -1;

}

// 加载证书和私钥

if (SSL_CTX_use_certificate_file(ctx, "server.crt", SSL_FILETYPE_PEM) <= 0) {

std::cerr << "Failed to load certificate: " << ERR_error_string(ERR_get_error(), nullptr) << "\n";

SSL_CTX_free(ctx);

return -1;

}

if (SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM) <= 0) {

std::cerr << "Failed to load private key: " << ERR_error_string(ERR_get_error(), nullptr) << "\n";

SSL_CTX_free(ctx);

return -1;

}

// 创建 socket

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

if (server_fd < 0) {

std::cerr << "Socket creation failed\n";

SSL_CTX_free(ctx);

return -1;

}

// 设置地址可重用

int opt = 1;

setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

// 设置服务器地址

sockaddr_in server_addr{};

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = INADDR_ANY;

server_addr.sin_port = htons(8443); // HTTPS 默认端口为 443,此处用 8443 避免权限问题

// 绑定地址

if (bind(server_fd, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) {

std::cerr << "Bind failed\n";

close(server_fd);

SSL_CTX_free(ctx);

return -1;

}

// 监听连接

if (listen(server_fd, 5) < 0) {

std::cerr << "Listen failed\n";

close(server_fd);

SSL_CTX_free(ctx);

return -1;

}

std::cout << "HTTPS server running on https://localhost:8443\n";

while (true) {

// 接受客户端连接

sockaddr_in client_addr{};

socklen_t client_len = sizeof(client_addr);

int client_fd = accept(server_fd, (sockaddr*)&client_addr, &client_len);

if (client_fd < 0) {

std::cerr << "Accept failed\n";

continue;

}

// 创建 SSL 连接

SSL* ssl = SSL_new(ctx);

SSL_set_fd(ssl, client_fd);

if (SSL_accept(ssl) <= 0) {

std::cerr << "SSL_accept failed: " << ERR_error_string(ERR_get_error(), nullptr) << "\n";

SSL_free(ssl);

close(client_fd);

continue;

}

// 接收客户端请求

char buffer[2048] = {0};

int bytes_received = SSL_read(ssl, buffer, sizeof(buffer) - 1);

if (bytes_received > 0) {

buffer[bytes_received] = '\0';

std::cout << "Received request:\n" << buffer << "\n";

}

// 构造 HTTPS 响应

std::string response =

"HTTP/1.1 200 OK\r\n"

"Content-Type: text/html\r\n"

"Connection: close\r\n"

"\r\n"

""

""

"C++ HTTPS Server"

"

Hello from C++ HTTPS Server!

"

"";

// 发送响应

SSL_write(ssl, response.c_str(), response.size());

// 清理

SSL_free(ssl);

close(client_fd);

}

// 清理

close(server_fd);

SSL_CTX_free(ctx);

cleanup_openssl();

return 0;

}

Https 客户端(Client):

#include

#include

#include

#include

#include

#include

#include

void init_openssl() {

SSL_load_error_strings();

OpenSSL_add_ssl_algorithms();

}

void cleanup_openssl() {

EVP_cleanup();

}

int main() {

// 初始化 OpenSSL

init_openssl();

SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());

if (!ctx) {

std::cerr << "SSL_CTX_new failed\n";

return -1;

}

// 创建 socket

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

if (sockfd < 0) {

std::cerr << "Socket creation failed\n";

SSL_CTX_free(ctx);

return -1;

}

// 设置服务器地址

sockaddr_in servaddr{};

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(443); // HTTPS 默认端口

inet_pton(AF_INET, "93.184.216.34", &servaddr.sin_addr); // example.com IP

// 连接服务器

if (connect(sockfd, (sockaddr*)&servaddr, sizeof(servaddr)) < 0) {

std::cerr << "Connection failed\n";

close(sockfd);

SSL_CTX_free(ctx);

return -1;

}

// 创建 SSL 连接

SSL* ssl = SSL_new(ctx);

SSL_set_fd(ssl, sockfd);

if (SSL_connect(ssl) <= 0) {

std::cerr << "SSL_connect failed: " << ERR_error_string(ERR_get_error(), nullptr) << "\n";

SSL_free(ssl);

close(sockfd);

SSL_CTX_free(ctx);

return -1;

}

// 设置服务器主机名以进行 SNI(服务器名称指示)

SSL_set_tlsext_host_name(ssl, "example.com");

// 构造 HTTPS GET 请求

std::string request =

"GET / HTTP/1.1\r\n"

"Host: example.com\r\n"

"Connection: close\r\n"

"\r\n";

if (SSL_write(ssl, request.c_str(), request.size()) <= 0) {

std::cerr << "SSL_write failed\n";

}

// 接收响应

char buffer[4096];

std::string response;

int bytes_received;

while ((bytes_received = SSL_read(ssl, buffer, sizeof(buffer) - 1)) > 0) {

buffer[bytes_received] = '\0';

response += buffer;

}

// 输出响应

std::cout << "HTTPS Response:\n" << response << "\n";

// 清理

SSL_free(ssl);

close(sockfd);

SSL_CTX_free(ctx);

cleanup_openssl();

return 0;

}

由于 HTTPS 是基于 TLS/SSL 的安全协议,代码需要使用 OpenSSL 处理加密通信。此示例适用于 Linux/macOS,Windows 需额外配置 OpenSSL 环境。

生成自签名证书和私钥

在 Linux/macOS 上生成自签名证书和私钥(需安装 OpenSSL):

openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes

回答提示时可直接回车,或设置 Common Name 为 localhost。

生成的 server.crt 和 server.key 需与 https_server.cpp 放在同一目录。

注意事项

自签名证书:生产环境应使用受信任的 CA 证书(如 Let’s Encrypt)。

端口权限:若使用 443 端口,需 root 权限或配置端口转发。

跨平台:Windows 需包含 并调用 WSAStartup() 初始化网络。

单线程:当前为单线程处理,生产环境建议多线程或事件驱动(如 epoll)。

证书验证:客户端需配置信任自签名证书,或禁用验证(不安全,仅测试用)。

📌 五 总结

5.1 TCP与UDP

TCP(传输控制协议)和 UDP(用户数据报协议)是计算机网络传输层的两大核心协议,在 计算机 开发中应用广泛。

特性TCPUDP是否连接面向连接(有握手)无连接(无需握手)可靠性可靠(保证顺序、不丢包)不可靠(可能丢包、乱序)传输速度相对较慢(开销大)较快(开销小)应用场景网页、文件传输、邮件、数据库等视频/语音通话、直播、游戏等是否流式传输是(按字节流)否(按数据报)

错误处理:

TCP:需处理连接断开(如ECONNRESET)、超时等异常。

UDP:需处理丢包(如应用层确认机制)、缓冲区溢出。

并发模型:

TCP:推荐使用异步 I/O(如Boost.Asio)或多线程处理连接。

UDP:单线程即可处理大量并发请求(无连接状态)。

跨平台兼容性:

Linux:可使用epoll(高性能)。

Windows:可使用IOCP(异步 I/O 完成端口)。

协议扩展:

TCP:可基于 TCP 实现自定义可靠协议(如 RPC 框架)。

UDP:可实现应用层可靠 UDP(如 QUIC 协议,已被 HTTP/3 采用)。

5.2 Http和Https

HTTP(超文本传输协议)和 HTTPS(超文本安全传输协议)是 Web 应用的基础协议,二者的核心差异在于安全性与性能。

特性HTTPHTTPS协议端口80443是否加密❌ 明文传输✅ 加密传输(SSL/TLS)安全性低,易被监听、篡改高,防窃听、防篡改、防伪造证书无需证书需要 SSL/TLS 数字证书URL 前缀http://https://性能开销较小稍高(但现代硬件/HTTP/2基本忽略不计)SEO(搜索排名)不利(被视为不安全)有利(Google 更推荐 HTTPS)

HTTP:不安全,仅适用于无敏感信息、局域网或调试。HTTPS:现代网站/应用的默认选择,保护用户数据、提升信任度和 SEO 排名。✅ 使用 Let’s Encrypt 可免费部署 HTTPS(配合 nginx / apache / C++ 服务框架等)。

无论是稳重可靠的 TCP,还是轻巧灵活的 UDP,亦或是支撑整个 Web 世界的 HTTP 与 HTTPS,它们都像高速公路上的不同车道,各司其职,共同构建起现代网络通信的基础框架。选择哪种协议,并没有“最优”,只有“最适合”。希望通过本篇文章,你能更有信心在不同业务场景下,合理选型、精准判断,写出更加稳定、安全、快速的网络应用。网络虽无形,协议有乾坤。理解它们,就是迈向更高技术水平的重要一步。

黄金推荐

dnfpk赛季什么时间结束2022
365bet官网哪里找

dnfpk赛季什么时间结束2022

🕒 08-14 💰 1900
上古卷轴5结婚攻略大全:结婚方法与步骤详解
365体育管网登录网站

上古卷轴5结婚攻略大全:结婚方法与步骤详解

🕒 08-30 💰 5336
遗器推荐
365体育管网登录网站

遗器推荐

🕒 10-06 💰 7845