HTTP(超文本传输协议)

HTTP原理和概念

HTTP(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。它是最常用的协议之一,用于在Web服务器和客户端之间传输数据。

HTTP步骤

  1. 建立连接:客户端通过URL与服务器建立TCP连接。
  2. 发送请求:客户端向服务器发送一个HTTP请求。
  3. 接收响应:服务器处理请求并返回一个HTTP响应。
  4. 关闭连接:在交换完数据后,关闭TCP连接(对于HTTP/1.1,连接可能会保持打开状态以用于后续请求)。

HTTP分类

  • HTTP/1.0
  • HTTP/1.1
  • HTTP/2
  • HTTP/3

HTTP用途

  • 网页浏览
  • 文件传输
  • Web服务API通信

C语言实现HTTP客户端

以下是一个简单的C语言实现的HTTP客户端示例,它发送一个GET请求到一个指定的URL,并打印出服务器的响应。请注意,这个示例仅用于教学目的,不包含错误处理和复杂的HTTP功能。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
    int sockfd; // 套接字文件描述符
    struct sockaddr_in serv_addr; // 服务器地址结构
    struct hostent *server; // 服务器主机信息
    char buffer[BUFFER_SIZE]; // 缓冲区
    if (argc < 3) { // 检查命令行参数
        fprintf(stderr, "Usage: %s hostname port\n", argv[0]);
        exit(1);
    }
    // 创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("ERROR opening socket");
        exit(1);
    }
    // 获取服务器主机信息
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr, "ERROR, no such host\n");
        exit(1);
    }
    // 初始化服务器地址结构
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(atoi(argv[2]));
    // 连接到服务器
    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("ERROR connecting");
        exit(1);
    }
    // 构造HTTP GET请求
    char *request = "GET / HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n";
    char request_str[BUFFER_SIZE];
    sprintf(request_str, request, argv[1]);
    // 发送HTTP请求
    write(sockfd, request_str, strlen(request_str));
    // 读取服务器响应
    int n;
    while ((n = read(sockfd, buffer, BUFFER_SIZE - 1)) > 0) {
        buffer[n] = '\0'; // 确保字符串结束
        printf("%s", buffer); // 打印响应
    }
    if (n < 0) {
        perror("ERROR reading from socket");
        exit(1);
    }
    // 关闭套接字
    close(sockfd);
    return 0;
}

这个代码片段创建了一个简单的HTTP客户端,它连接到指定的服务器和端口,发送一个HTTP GET请求,并打印出服务器的响应。每行代码都有注释来解释它的作用。这个程序不处理HTTP响应的解析,只是简单地打印出接收到的所有数据。在实际应用中,你需要解析HTTP响应头来处理状态码、内容类型等。

报头解析

HTTP报头解析涉及读取HTTP响应的头部部分,并从中提取出各个字段及其值。以下是一个HTTP响应头的示例及其解析过程。
假设我们接收到以下HTTP响应头:

HTTP/1.1 200 OK
Date: Mon, 27 Sep 2021 12:28:53 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
Content-Length: 12638
Connection: close

以下是解析过程,使用中横杠画出解析字段宽度:

HTTP/1.1 200 OK
----------------- Status Line (包含协议版本、状态码和状态消息)
Date: Mon, 27 Sep 2021 12:28:53 GMT
-------- Field Name (日期字段)
-------------------------- Field Value (日期值)
Server: Apache/2.4.41 (Ubuntu)
------- Field Name (服务器字段)
------------------------ Field Value (服务器信息)
Content-Type: text/html; charset=UTF-8
---------- Field Name (内容类型字段)
------------------------------- Field Value (内容类型和字符集)
Content-Length: 12638
------------- Field Name (内容长度字段)
------------------- Field Value (内容长度值)
Connection: close
----------- Field Name (连接字段)
------------------ Field Value (连接指示)

下面是一个简单的C语言函数,用于解析HTTP响应头中的各个字段:

#include <stdio.h>
#include <string.h>
#define MAX_HEADER_SIZE 1024
// 解析HTTP响应头中的字段
void parse_http_headers(const char *headers) {
    char line[MAX_HEADER_SIZE];
    const char *end_of_headers = strstr(headers, "\r\n\r\n"); // HTTP头以两个CRLF结束
    const char *line_start = headers;
    // 遍历每一行
    while (line_start < end_of_headers && line_start != NULL) {
        const char *line_end = strstr(line_start, "\r\n");
        if (line_end == NULL) break;
        size_t line_length = line_end - line_start;
        if (line_length >= MAX_HEADER_SIZE) {
            printf("Header line too long.\n");
            return;
        }
        memcpy(line, line_start, line_length);
        line[line_length] = '\0'; // 确保字符串结束
        // 提取字段名和值
        char *field_value = strchr(line, ':');
        if (field_value != NULL) {
            *field_value = '\0'; // 切断字段名
            field_value++; // 跳过冒号
            while (*field_value == ' ') field_value++; // 跳过空格
            // 打印字段名和值
            printf("%s: %s\n", line, field_value);
        }
        line_start = line_end + 2; // 移动到下一行开始
    }
}
int main() {
    const char *http_headers = 
        "HTTP/1.1 200 OK\r\n"
        "Date: Mon, 27 Sep 2021 12:28:53 GMT\r\n"
        "Server: Apache/2.4.41 (Ubuntu)\r\n"
        "Content-Type: text/html; charset=UTF-8\r\n"
        "Content-Length: 12638\r\n"
        "Connection: close\r\n"
        "\r\n"; // 注意最后的CRLF
    parse_http_headers(http_headers);
    return 0;
}

在这个函数中,我们通过遍历每一行来解析HTTP头。我们找到每行的结束(由CRLF标记),并从中提取字段名和值。字段名和值由冒号分隔,且值前可能包含空格。解析后,我们打印出字段名和值。这个函数假设HTTP头是正确的,并且不包含任何错误处理。在真实的应用中,你需要添加更多的错误检查和边界条件处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

请向我看齐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值