C 语言实现 HTTP 和 HTTPS 通信的例程

HTTP 通信例程

HTTP 是一种明文传输协议,在 C 语言中可以使用 socket 编程来实现简单的 HTTP 请求。以下是一个示例代码,用于向指定的 HTTP 服务器发送 GET 请求并接收响应:

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define BUFFER_SIZE 1024

int main() {
    int sockfd;
    struct sockaddr_in server_addr;
    char buffer[BUFFER_SIZE];
    char request[BUFFER_SIZE];

    // 创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket creation failed");
        return -1;
    }

    // 设置服务器地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(80); // HTTP 默认端口
    if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {
        perror("invalid address or address not supported");
        return -1;
    }

    // 连接到服务器
    if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("connection failed");
        return -1;
    }

    // 构建 HTTP 请求
    snprintf(request, sizeof(request), "GET / HTTP/1.1\r\n"
                                       "Host: 127.0.0.1\r\n"
                                       "Connection: close\r\n\r\n");

    // 发送请求
    if (send(sockfd, request, strlen(request), 0) == -1) {
        perror("send failed");
        return -1;
    }

    // 接收响应
    ssize_t bytes_received;
    while ((bytes_received = recv(sockfd, buffer, sizeof(buffer) - 1, 0)) > 0) {
        buffer[bytes_received] = '\0';
        printf("%s", buffer);
    }

    // 关闭套接字
    close(sockfd);

    return 0;
}

代码说明

  1. 创建套接字 :使用 socket 函数创建一个 TCP 套接字。
  2. 设置服务器地址:设置服务器的 IP 地址和端口号。
  3. 连接到服务器 :使用 connect 函数连接到服务器。
  4. 构建 HTTP 请求:构建一个简单的 HTTP GET 请求。
  5. 发送请求 :使用 send 函数发送请求。
  6. 接收响应 :使用 recv 函数接收服务器的响应。
  7. 关闭套接字 :使用 close 函数关闭套接字。

HTTPS 通信例程

HTTPS 是基于 HTTP 的安全传输协议,需要使用 SSL/TLS 进行加密。在 C 语言中可以使用 OpenSSL 库来实现 HTTPS 通信。以下是一个示例代码,用于向指定的 HTTPS 服务器发送 GET 请求并接收响应:

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define BUFFER_SIZE 1024

void init_openssl() {
    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
}

void cleanup_openssl() {
    EVP_cleanup();
    ERR_free_strings();
}

SSL_CTX *create_context() {
    const SSL_METHOD *method;
    SSL_CTX *ctx;

    method = SSLv23_client_method();
    ctx = SSL_CTX_new(method);
    if (!ctx) {
        perror("Unable to create SSL context");
        ERR_print_errors_fp(stderr);
        return NULL;
    }

    return ctx;
}

void configure_context(SSL_CTX *ctx) {
    SSL_CTX_set_ecdh_auto(ctx, 1);

    // 验证服务器证书
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    if (SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ssl/certs") != 1) {
        ERR_print_errors_fp(stderr);
    }
}

int main() {
    int sockfd;
    struct sockaddr_in server_addr;
    char buffer[BUFFER_SIZE];
    char request[BUFFER_SIZE];
    SSL_CTX *ctx;
    SSL *ssl;

    // 初始化 OpenSSL
    init_openssl();

    // 创建 SSL 上下文
    ctx = create_context();
    if (!ctx) {
        cleanup_openssl();
        return -1;
    }

    // 配置 SSL 上下文
    configure_context(ctx);

    // 创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket creation failed");
        SSL_CTX_free(ctx);
        cleanup_openssl();
        return -1;
    }

    // 设置服务器地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(443); // HTTPS 默认端口
    if (inet_pton(AF_INET, "www.example.com", &server_addr.sin_addr) <= 0) {
        perror("invalid address or address not supported");
        close(sockfd);
        SSL_CTX_free(ctx);
        cleanup_openssl();
        return -1;
    }

    // 连接到服务器
    if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("connection failed");
        close(sockfd);
        SSL_CTX_free(ctx);
        cleanup_openssl();
        return -1;
    }

    // 创建 SSL 连接
    ssl = SSL_new(ctx);
    if (!ssl) {
        perror("unable to create SSL connection");
        close(sockfd);
        SSL_CTX_free(ctx);
        cleanup_openssl();
        return -1;
    }

    // 将 SSL 连接与套接字关联
    if (SSL_set_fd(ssl, sockfd) != 1) {
        perror("unable to set SSL fd");
        SSL_free(ssl);
        close(sockfd);
        SSL_CTX_free(ctx);
        cleanup_openssl();
        return -1;
    }

    // 执行 SSL 握手
    if (SSL_connect(ssl) != 1) {
        ERR_print_errors_fp(stderr);
        SSL_free(ssl);
        close(sockfd);
        SSL_CTX_free(ctx);
        cleanup_openssl();
        return -1;
    }

    // 构建 HTTP 请求
    snprintf(request, sizeof(request), "GET / HTTP/1.1\r\n"
                                       "Host: www.example.com\r\n"
                                       "Connection: close\r\n\r\n");

    // 发送请求
    if (SSL_write(ssl, request, strlen(request)) <= 0) {
        ERR_print_errors_fp(stderr);
        SSL_free(ssl);
        close(sockfd);
        SSL_CTX_free(ctx);
        cleanup_openssl();
        return -1;
    }

    // 接收响应
    ssize_t bytes_received;
    while ((bytes_received = SSL_read(ssl, buffer, sizeof(buffer) - 1)) > 0) {
        buffer[bytes_received] = '\0';
        printf("%s", buffer);
    }

    // 关闭 SSL 连接
    SSL_shutdown(ssl);
    SSL_free(ssl);

    // 关闭套接字
    close(sockfd);

    // 清理 OpenSSL
    SSL_CTX_free(ctx);
    cleanup_openssl();

    return 0;
}

代码说明

  1. 初始化 OpenSSL :调用 init_openssl 函数初始化 OpenSSL 库。
  2. 创建 SSL 上下文 :调用 create_context 函数创建 SSL 上下文。
  3. 配置 SSL 上下文 :调用 configure_context 函数配置 SSL 上下文,包括验证服务器证书。
  4. 创建套接字 :使用 socket 函数创建一个 TCP 套接字。
  5. 设置服务器地址:设置服务器的 IP 地址和端口号。
  6. 连接到服务器 :使用 connect 函数连接到服务器。
  7. 创建 SSL 连接 :使用 SSL_new 函数创建 SSL 连接,并使用 SSL_set_fd 函数将 SSL 连接与套接字关联。
  8. 执行 SSL 握手 :使用 SSL_connect 函数执行 SSL 握手。
  9. 构建 HTTP 请求:构建一个简单的 HTTP GET 请求。
  10. 发送请求 :使用 SSL_write 函数发送请求。
  11. 接收响应 :使用 SSL_read 函数接收服务器的响应。
  12. 关闭 SSL 连接 :使用 SSL_shutdownSSL_free 函数关闭 SSL 连接。
  13. 关闭套接字 :使用 close 函数关闭套接字。
  14. 清理 OpenSSL :调用 cleanup_openssl 函数清理 OpenSSL 库。

编译和运行

HTTP 例程
复制代码
gcc http_example.c -o http_example
./http_example
HTTPS 例程
复制代码
gcc https_example.c -o https_example -lssl -lcrypto
./https_example

以上代码仅是简单示例,实际应用中可能需要更多的错误处理和安全性检查。

相关推荐
凉、介1 小时前
Flash 块设备驱动开发
c语言·驱动开发·笔记·学习·操作系统·嵌入式
itman3012 小时前
C语言字符串必知:末尾有个隐藏的\0,新手易踩坑
c语言·字符串·内存管理·库函数·指针操作
海参崴-3 小时前
C语言与C++语言发展历史详解
java·c语言·c++
kelleyv3 小时前
C语言为何跨平台难?编译后换系统就跑不了
c语言·java虚拟机·字节码·跨平台性·本地代码
一路向北he3 小时前
esp32库依赖
c语言·c++·算法
海参崴-4 小时前
深入剖析C语言结构体存储规则:内存对齐原理与实战详解
java·c语言·开发语言
小柯博客4 小时前
从零开始打造 OpenSTLinux 6.6 Yocto 系统 - STM32MP2(基于STM32CubeMX)(八)
c语言·git·stm32·单片机·嵌入式硬件·嵌入式·yocto
iFlyCai12 小时前
C语言中的指针
c语言·数据结构·算法
良木生香15 小时前
【C++初阶】:C++类和对象(下):构造函数promax & 类型转换 & static & 友元 & 内部类 & 匿名对象 & 超级优化
c语言·开发语言·c++
无巧不成书021816 小时前
C语言零基础速通指南 | 1小时从入门到跑通完整项目
c语言·开发语言·编程实战·c语言入门·零基础编程·c语言速通