c语言 socket 实现 https协议

261 阅读2分钟
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define PORT 443
#define BUFFER_SIZE 1024

SSL_CTX *init_server_ctx(void) {
    SSL_CTX *ctx;

    // 初始化SSL库
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();

    // 创建SSL上下文
    ctx = SSL_CTX_new(SSLv23_server_method());
    if (ctx == NULL) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    // 加载服务器证书和私钥
    if (SSL_CTX_use_certificate_file(ctx, "server.crt", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    if (SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    return ctx;
}

void handle_client(SSL *ssl) {
    char buffer[BUFFER_SIZE];
    memset(buffer, 0, sizeof(buffer));

    // 读取客户端的请求
    SSL_read(ssl, buffer, sizeof(buffer) - 1);
    printf("Received request:\n%s\n", buffer);

    // 构造HTTP响应
    char response[] = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><body><h1>Hello, this is a simple HTTPS server</h1></body></html>";

    // 发送响应给客户端
    SSL_write(ssl, response, sizeof(response) - 1);

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

int main() {
    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    SSL_CTX *ctx;

    // 初始化服务器SSL上下文
    ctx = init_server_ctx();

    // 创建套接字
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("Error creating socket");
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址结构
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);

    // 绑定套接字到指定端口
    if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("Error binding socket");
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(server_socket, 10) == -1) {
        perror("Error listening on socket");
        exit(EXIT_FAILURE);
    }

    printf("Server listening on port %d (HTTPS)...\n", PORT);

    while (1) {
        // 接受客户端连接
        client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len);
        if (client_socket == -1) {
            perror("Error accepting connection");
            continue;
        }

        // 创建SSL连接
        SSL *ssl = SSL_new(ctx);
        SSL_set_fd(ssl, client_socket);

        // SSL握手
        if (SSL_accept(ssl) <= 0) {
            ERR_print_errors_fp(stderr);
            close(client_socket);
            continue;
        }

        // 处理客户端请求
        handle_client(ssl);
    }

    // 关闭服务器套接字
    close(server_socket);
    SSL_CTX_free(ctx);

    return 0;
}

请注意,上述代码中使用了服务器证书和私钥,你需要使用实际的证书和私钥文件,并确保它们位于指定的路径。这个例子使用了自签名证书和私钥,不适用于生产环境。在实际应用中,请使用由可信的证书颁发机构(CA)颁发的证书。

在实际项目中,你可能需要更复杂的错误处理、安全性和性能优化。此外,这个示例仅仅是一个基本的HTTPS服务器,不涉及到多线程或多进程的处理,因此对并发请求的处理相对简单。在实际应用中,你可能需要使用线程或进程池来处理多个客户端连接。