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

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

相关推荐
季明洵2 小时前
C语言实现单链表
c语言·开发语言·数据结构·算法·链表
浅念-2 小时前
C语言编译与链接全流程:从源码到可执行程序的幕后之旅
c语言·开发语言·数据结构·经验分享·笔记·学习·算法
爱吃生蚝的于勒3 小时前
【Linux】进程信号之捕捉(三)
linux·运维·服务器·c语言·数据结构·c++·学习
The森3 小时前
Linux IO 模型纵深解析 01:从 Unix 传统到 Linux 内核的 IO 第一性原理
linux·服务器·c语言·经验分享·笔记·unix
C++ 老炮儿的技术栈4 小时前
Qt 编写 TcpClient 程序 详细步骤
c语言·开发语言·数据库·c++·qt·算法
wangjialelele4 小时前
Linux下的IO操作以及ext系列文件系统
linux·运维·服务器·c语言·c++·个人开发
wengqidaifeng7 小时前
数据结构(三)栈和队列(上)栈:计算机世界的“叠叠乐”
c语言·数据结构·数据库·链表
VekiSon7 小时前
Linux内核驱动——设备树原理与应用
linux·c语言·arm开发·嵌入式硬件
BlackQid7 小时前
深入理解指针Part5——回调函数及应用
c语言
日拱一卒——功不唐捐7 小时前
字符串匹配:暴力法和KMP算法(C语言)
c语言·算法