MST

星途 面试题库

面试题:C语言处理HTTP响应并优化

在Linux下,用C语言编写代码处理HTTP响应,要求不仅能正确解析响应头和响应体,还要考虑如何优化内存使用和网络I/O操作,例如在接收大文件响应时避免内存溢出,并且说明你所采用优化策略的原理。
42.1万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

代码示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>

#define BUFFER_SIZE 1024

// 解析HTTP响应头
void parse_headers(char *buffer, char *headers) {
    char *end = strstr(buffer, "\r\n\r\n");
    if (end) {
        int headers_length = end - buffer;
        strncpy(headers, buffer, headers_length);
        headers[headers_length] = '\0';
    }
}

// 处理HTTP响应
void handle_http_response(int sockfd) {
    char buffer[BUFFER_SIZE];
    ssize_t bytes_read;
    char headers[BUFFER_SIZE];
    int body_fd = open("response_body", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (body_fd == -1) {
        perror("open");
        return;
    }

    // 读取并解析HTTP响应头
    bytes_read = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
    if (bytes_read <= 0) {
        perror("recv");
        close(body_fd);
        return;
    }
    buffer[bytes_read] = '\0';
    parse_headers(buffer, headers);
    printf("HTTP Headers:\n%s\n", headers);

    // 跳过响应头和空行
    char *end_of_headers = strstr(buffer, "\r\n\r\n");
    if (end_of_headers) {
        ssize_t offset = end_of_headers - buffer + 4;
        bytes_read -= offset;
        if (bytes_read > 0) {
            write(body_fd, end_of_headers + 4, bytes_read);
        }
    }

    // 逐块读取并写入响应体,避免内存溢出
    while ((bytes_read = recv(sockfd, buffer, sizeof(buffer), 0)) > 0) {
        write(body_fd, buffer, bytes_read);
    }

    if (bytes_read < 0) {
        perror("recv");
    }

    close(body_fd);
}

int main() {
    int sockfd;
    struct sockaddr_in servaddr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    memset(&servaddr.sin_zero, 0, sizeof(servaddr.sin_zero));

    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(80);
    servaddr.sin_addr.s_addr = inet_addr("192.168.1.100"); // 替换为实际服务器IP

    if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) {
        perror("connect failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 发送HTTP请求
    const char *request = "GET / HTTP/1.1\r\nHost: 192.168.1.100\r\n\r\n";
    send(sockfd, request, strlen(request), 0);

    handle_http_response(sockfd);

    close(sockfd);
    return 0;
}

优化策略及原理

  1. 逐块读取响应体:在处理大文件响应时,采用逐块读取的方式,每次读取固定大小(如BUFFER_SIZE)的数据,并立即写入文件。这样避免了一次性将整个大文件读入内存,防止内存溢出。其原理是通过控制每次读入内存的数据量,使内存使用保持在可控范围内。
  2. 及时处理和丢弃已解析的头部:解析完HTTP响应头后,立即将其从缓冲区中处理(如打印或保存到其他地方),并跳过头部和空行直接处理响应体。这减少了不必要的内存占用,因为不再需要在内存中长时间保留已经解析过的头部数据。