Linux C语言如何实现HTTPS通信?

99ANYc3cd6
预计阅读时长 23 分钟
位置: 首页 C语言 正文

下面我将从 “为什么需要 HTTPS”“核心库介绍”“三种实现方式(从易到难)” 以及 “完整代码示例” 几个方面,为你详细讲解如何在 Linux C 语言中实现 HTTPS 客户端。

linux c语言https
(图片来源网络,侵删)

为什么需要 HTTPS?

HTTPS = HTTP + SSL/TLS,它解决了 HTTP 的两个核心问题:

  • 机密性:防止数据在传输过程中被窃听,SSL/TLS 会加密你的请求和响应内容。
  • 完整性:防止数据在传输过程中被篡改,SSL/TLS 会验证数据是否在传输途中被修改过。
  • 身份验证:确保你正在和正确的服务器通信,而不是一个冒名顶替的中间人。

核心库介绍

在 Linux C 生态中,有几种主流的库可以实现 HTTPS 功能,各有优劣:

库名 特点 优点 缺点 适用场景
libcurl 高级、易用、功能强大的 URL 传输库 推荐新手,封装了底层细节,API 简单,支持几乎所有协议(HTTP, HTTPS, FTP, SMTP...),稳定可靠。 相对“重量级”,依赖可能较多。 大多数需要网络通信的 C/C++ 项目,特别是快速开发。
OpenSSL 底层、功能全面的 SSL/TLS 加密库 功能最强大、最灵活,可以实现各种复杂的加密、证书验证等操作。 API 复杂且晦涩,学习曲线陡峭,容易出错。 需要高度定制化加密逻辑、或实现自己的协议(如自定义 MQTT over TLS)的场景。
GnuTLS 另一个开源的 SSL/TLS 库 功能与 OpenSSL 类似,API 相对 OpenSSL 更友好一些。 生态和社区规模小于 OpenSSL。 不想使用 OpenSSL 时的替代方案。

对于绝大多数开发者,强烈推荐从 libcurl 开始。 它能让你用最少的代码实现 HTTPS 通信,只有在有特殊需求时,才去考虑直接使用 OpenSSL。


三种实现方式(从易到难)

我们将重点介绍 libcurl 的使用,因为它是最实用的。

linux c语言https
(图片来源网络,侵删)

使用 libcurl (推荐)

libcurl 是一个客户端的 URL 传输库,它为你处理了所有复杂的 SSL/TLS 握手、加密、解密过程,你只需要像使用 HTTP 一样,告诉它一个 https:// 开头的 URL 即可。

步骤 1: 安装 libcurl

在基于 Debian/Ubuntu 的系统上:

sudo apt-get update
sudo apt-get install libcurl4-openssl-dev

在基于 RHEL/CentOS 的系统上:

sudo yum install libcurl-devel

步骤 2: 编写 C 代码

libcurl 的使用模式通常是固定的:

linux c语言https
(图片来源网络,侵删)
  1. curl_global_init(): 全局初始化。
  2. curl_easy_init(): 初始化一个 easy handle。
  3. `curl_easy_setopt()这是最关键的一步**,通过设置各种选项来配置本次请求(如 URL、回调函数、超时等)。
  4. curl_easy_perform(): 执行请求。
  5. curl_easy_cleanup(): 清理 easy handle。
  6. curl_global_cleanup(): 全局清理。

回调函数 write_callback 用于接收服务器返回的数据。

完整代码示例 (https_get.c)

这个例子会向 https://example.com 发送一个 GET 请求,并将响应内容打印到标准输出。

#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
// 回调函数,用于接收 libcurl 传递过来的数据
// size_t 是数据项的大小,nmemb 是数据项的数量,size * nmemb 是这一块数据的总大小
// contents 是一个指针,指向 libcurl 分配的内存块,用于存放接收到的数据
// userp 是用户自定义指针,我们在 setopt 中传入
size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
    // 将接收到的数据追加到 userp 指向的字符串中
    // strncat 会自动在末尾添加 '\0'
    strncat((char *)userp, contents, size * nmemb);
    return size * nmemb; // 必须返回接收到的字节数
}
int main(void) {
    CURL *curl;
    CURLcode res;
    // 用于存储响应数据的缓冲区
    char response_buffer[4096] = {0}; // 初始化为全 0
    // 1. 全局初始化
    curl_global_init(CURL_GLOBAL_ALL);
    // 2. 初始化一个 easy handle
    curl = curl_easy_init();
    if (curl) {
        // 3. 设置 easy handle 的选项
        curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
        // 设置我们的回调函数来处理响应数据
        // CURLOPT_WRITEFUNCTION: 指定回调函数
        // CURLOPT_WRITEDATA: 指定传递给回调函数的 userp 参数
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)response_buffer);
        // (可选) 设置一个 User-Agent
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
        // (可选) 设置超时时间 (秒)
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
        // (可选) 禁用 SSL/TLS 证书验证 (仅用于测试!)
        // 在生产环境中,你应该验证证书!
        // curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        // curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
        // 4. 执行请求
        res = curl_easy_perform(curl);
        // 检查执行结果
        if (res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        } else {
            // 打印我们接收到的数据
            printf("Response received:\n%s\n", response_buffer);
            // (可选) 获取响应码
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            printf("HTTP Response Code: %ld\n", response_code);
        }
        // 5. 清理 easy handle
        curl_easy_cleanup(curl);
    }
    // 6. 全局清理
    curl_global_cleanup();
    return 0;
}

步骤 3: 编译和运行

编译时,你需要链接 libcurl 库。

# -o 指定输出文件名,-lcurl 链接 curl 库
gcc https_get.c -o https_get -lcurl

运行:

./https_get

你将看到 example.com 的 HTML 内容。


直接使用 OpenSSL (高级)

直接使用 OpenSSL 意味着你需要自己处理 TCP 连接、SSL/TLS 握手、发送 HTTP 请求、解析响应等所有细节,这非常复杂,但能提供最大的控制权。

核心流程:

  1. 初始化 OpenSSL (SSL_library_init, OpenSSL_add_all_algorithms, SSL_load_error_strings)。
  2. 创建 SSL 上下文 (SSL_CTX_new),这相当于 SSL/TLS 的“配置模板”。
  3. 创建套接字 (socket, connect),先建立普通的 TCP 连接。
  4. 基于 TCP 套接字创建 SSL 连接 (SSL_new, SSL_set_fd, SSL_connect),这一步会执行 TLS 握手。
  5. 发送和接收加密数据 (SSL_write, SSL_read),此时发送的所有数据都会被自动加密。
  6. 关闭连接 (SSL_shutdown, close)。
  7. 释放资源 (SSL_free, SSL_CTX_free)。

由于这个过程非常繁琐,代码量会很大,这里就不提供完整示例了,但你可以参考 OpenSSL 官方网站的示例代码:https://www.openssl.org/docs/manmaster/man3/SSL_connect.html


使用更现代的 C++ 库 (如 Cpr)

如果你的项目是 C++ 的,可以考虑使用更现代、更易用的 HTTP/HTTPS 客户端库,Cpr (C++ Requests),它的 API 设计灵感来源于 Python 的 requests 库,非常直观。

示例 (Cpr):

#include <cpr/cpr.h>
#include <iostream>
int main() {
    cpr::Response r = cpr::Get(cpr::Url{"https://example.com"},
                               cpr::Timeout{10000},
                               cpr::Header{{"User-Agent", "cpp-cpr-agent/1.0"}});
    if (r.status_code == 200) {
        std::cout << "Response received:\n" << r.text << std::endl;
        std::cout << "HTTP Response Code: " << r.status_code << std::endl;
    } else {
        std::cerr << "Request failed with status code: " << r.status_code << std::endl;
    }
    return 0;
}

编译和安装 Cpr 也相对简单,它通常会处理好底层的 libcurllibcurl-asio 依赖。


证书验证的重要性

在使用 libcurl 时,默认情况下它会验证服务器的 SSL 证书,以确保你连接的是合法的服务器,而不是一个伪造的“中间人”服务器,这个过程需要系统的 CA (Certificate Authority) 证书包。

如果你遇到证书验证错误:

  • 最佳实践:将服务器的证书(或 CA 证书)下载到本地,然后使用 CURLOPT_CAINFO 选项指定证书路径。
    curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/cacert.pem");
  • 临时解决方案(仅用于开发/测试!):可以禁用证书验证。
    // 警告:这会使你的连接不安全!
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

    千万不要在生产环境中使用这种方式!

方法 难度 开发效率 灵活性 推荐度
libcurl ⭐⭐⭐⭐⭐ (首选)
OpenSSL 极高 极高 ⭐⭐ (特殊需求时)
C++ (Cpr) 极高 ⭐⭐⭐⭐⭐ (C++ 项目首选)

对于 Linux C 语言的 HTTPS 开发,libcurl 是无可争议的最佳选择,它为你屏蔽了底层复杂性,让你能专注于业务逻辑,同时保证了功能的强大和稳定,从上面的 https_get.c 示例开始,你就可以轻松地在自己的 C 项目中集成 HTTPS 功能了。

-- 展开阅读全文 --
头像
织梦列表页分页数量如何自定义设置?
« 上一篇 前天
dede采集图集图片,发布时如何正确处理?
下一篇 » 前天

相关文章

取消
微信二维码
支付宝二维码

目录[+]