Linux进阶篇:HTTP协议

开篇:本文解决什么问题?

  • 拆解HTTP协议的核心特性与传输流程
  • 区分HTTP长连接与短连接的适用场景
  • 实现一个能处理静态资源的HTTP服务器

一、HTTP协议基础

1 什么是HTTP?

HTTP(超文本传输协议)是基于TCP/IP的应用层协议 ,主要用于客户端与服务器之间的静态资源(如HTML、图片)传输,遵循请求-响应的交互模式。

2 HTTP的核心特性

无状态:每次请求相互独立,服务器不存储客户端的会话信息

明文传输:数据在网络中以明文形式传输,安全性较低

基于TCP:依赖TCP的可靠传输特性,通信前需完成三次握手建立连接

3 无状态的弥补方案

为解决无状态导致的用户身份识别问题,方案如下:

Cookie:服务器通过响应头向客户端下发小型数据,客户端后续请求自动携带

Session:服务器为用户创建专属会话存储状态,通过Cookie传递 sessionID 匹配用户

Token:客户端登录后获取加密令牌,后续请求携带令牌完成身份认证,无需服务器存储会话

4 HTTP与HTTPS的对比

|------|---------|---------------|
| 对比维度 | HTTP | HTTPS |
| 安全性 | 低,明文传输 | 高,基于SSL/TLS加密 |
| 默认端口 | 80 | 443 |
| 地址标识 | http:// | https:// |
| 适用场景 | 普通网页浏览 | 支付、登录等敏感数据传输 |

二、传输过程

1. 建立TCP连接

客户端与服务器通过TCP三次握手建立可靠连接。

2. 发送HTTP请求

客户端发送符合协议格式的请求数据,包含请求行、请求头、请求体三部分。

请求行:如 GET /index.html HTTP/1.1 ,包含请求方法、资源路径、协议版本

请求头:携带附加信息(如浏览器类型、Cookie)

请求体:仅POST请求存在,用于传输表单、JSON等数据

3. 服务器处理并响应

服务器解析请求,返回响应数据,包含响应行、响应头、响应体三部分。

响应行:如 HTTP/1.1 200 OK ,包含协议版本、状态码、状态描述

响应头:携带数据长度、数据类型等信息

响应体:核心资源内容(如HTML代码、图片二进制数据)

4. 关闭TCP连接

短连接模式下,一次请求响应后通过四次挥手断开连接。

三、长连接与短连接

|------|---------------------|------------------------------|
| 对比维度 | 短连接 | 长连接 |
| 生命周期 | 一次请求-响应后关闭TCP连接 | 连接建立后可承载多次请求,空闲超时后关闭 |
| 协议标识 | HTTP/1.0 | HTTP/1.1,通过 keep-alive 头字段标识 |
| 资源消耗 | 高,频繁建立/断开连接 | 低,复用连接减少开销 |
| 适用场景 | 简单页面 | 复杂页面(多图片、CSS、JS资源加载) |

四、辅助协议

DNS:将域名转换为IP地址,解决"记域名比记IP更方便"的问题

ARP:将IP地址转换为MAC地址,实现局域网内设备寻址

DHCP:自动为设备分配IP地址、网关、DNS等网络配置

五、静态资源解析

1 核心概念

index.html:网站默认首页,用户访问域名时若未指定文件,服务器自动返回该文件

HTML:超文本标记语言,通过标签构建网页结构,核心标签包含 <html> 、 <head> 、 <body>

2 lseek函数(文件指针操作)

在处理静态文件时, lseek 用于移动文件读写指针,实现文件随机访问,函数原型:

cpp 复制代码
off_t lseek(int fd, off_t offset, int whence);

fd:文件描述符

offset:偏移字节数

whence:基准位置( SEEK_SET -文件开头、 SEEK_CUR -当前位置、 SEEK_END -文件末尾)

六、实现HTTP服务器

1 功能说明

本代码基于TCP套接字和HTTP/1.0协议,实现一个简易HTTP服务器,核心功能如下:

  1. 监听本地 127.0.0.1:80 端口,接收 客户端HTTP请求

  2. 解析GET请求中的资源路径,读取 对应本地静态文件

  3. 若文件存在,返回 200 OK 状态码和文件内容

  4. 若文件不存在,返回 404 Not Found 状态码和预设的404错误页面

  5. 单线程阻塞处理,同一时间仅能响应一个客户端请求

2 代码实现

(1)头文件与宏定义
cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>

#define DATALENGTH 1024 // 数据缓冲区大小
#define PATHLENGTH 128 // 文件路径最大长度
(2)发送HTTP响应头
cpp 复制代码
// 功能:构造并发送HTTP响应头
// 参数:c 客户端通信套接字,size 响应体大小,flag 文件存在标识(1存在/0不存在)
void SendHeadData(int c, int size, int flag) {
    char buff[DATALENGTH] = "HTTP/1.0";
    // 根据文件状态设置响应状态码
    if (flag) {
        strcat(buff, "200 OK\r\n");
    } else {
        strcat(buff, "404 Not Found\r\n");
    }
    // 填充响应头字段
    strcat(buff, "Server: MyWeb/1.0\r\n");
    strcat(buff, "Content-Length: ");
    sprintf(buff + strlen(buff), "%d", size);
    strcat(buff, "\r\n");
    strcat(buff, "Content-Type: text/html;charset=utf-8\r\n");
    strcat(buff, "\r\n"); // 响应头与响应体的分隔符(必须有)
    // 发送响应头
    send(c, buff, strlen(buff), 0);
}
(3)发送文件内容
cpp 复制代码
// 功能:读取文件内容并发送给客户端(作为响应体)
// 参数:c 客户端通信套接字,fd 打开的文件描述符
void SendFileData(int c, int fd) {
    while (1) {
        char buff[DATALENGTH] = {0};
        // 分块读取文件内容
        ssize_t n = read(fd, buff, DATALENGTH - 1);
        // 读取完毕或失败则退出循环
        if (n <= 0) {
            break;
        }
        // 发送读取到的文件内容
        send(c, buff, n, 0);
    }
}
(4)处理客户端请求
cpp 复制代码
// 功能:接收并解析客户端HTTP请求,处理静态文件读取与响应
// 参数:c 客户端通信套接字
void DealClientData(int c) {
    char requestBuff[DATALENGTH] = {0};
    // 接收客户端请求数据
    int n = recv(c, requestBuff, DATALENGTH - 1, 0);
    if (n <= 0) {
        return;
    }
    // 解析HTTP请求行,提取资源路径
    // 示例请求行:GET /index.html HTTP/1.1 → 切割后获取 /index.html
    char *file = strtok(requestBuff, " ");
    file = strtok(NULL, " ");
    int flag = 1; // 文件存在标识,默认存在
    char path[PATHLENGTH] = "./"; // 本地文件根路径
    strcat(path, file); // 拼接完整文件路径
    // 以只读方式打开请求的文件
    int fd = open(path, O_RDONLY);
    // 文件不存在则打开404错误页面
    if (fd == -1) {
        fd = open("./404.html", O_RDONLY);
        flag = 0;
    }
    // 获取文件状态(包含文件大小)
    struct stat st;
    fstat(fd, &st);
    // 发送HTTP响应头
    SendHeadData(c, st.st_size, flag);
    // 发送文件内容
    SendFileData(c, fd);
    // 关闭文件描述符
    close(fd);

}
(5)初始化服务器套接字
cpp 复制代码
// 功能:创建、绑定、监听TCP套接字,完成服务器初始化
// 返回值:成功返回监听套接字,失败返回-1
int InitSocket() {
    // 1. 创建TCP套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        return -1;
    }
    // 2. 配置服务器地址结构体
    struct sockaddr_in saddr;
    memset(&saddr, 0, sizeof(saddr));
    saddr.sin_family = AF_INET; // IPv4协议族
    saddr.sin_port = htons(80); // HTTP默认端口(转换为网络字节序)
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 本地回环地址
    // 3. 绑定套接字与地址端口
    int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
    if (res == -1) {
        return -1;
    }
    // 4. 开启监听(5为半连接队列最大长度)
    res = listen(sockfd, 5);
    if (res == -1) {
        return -1;
    }
    return sockfd;
}
(6)主函数
cpp 复制代码
// 功能:程序入口,启动服务器并循环接收客户端连接
int main() {
    // 初始化服务器套接字
    int sockfd = InitSocket();
    // 断言检查初始化是否成功,失败则终止程序
    assert(sockfd != -1);
    // 循环等待客户端连接(服务器常驻运行)
    while (1) {
        struct sockaddr_in caddr; // 客户端地址结构体
        socklen_t len = sizeof(caddr);
        // 接受客户端连接(阻塞等待)
        int c = accept(sockfd, (struct sockaddr*)&caddr, &len);
        if (c < 0) {
            continue;
        }
        // 处理客户端请求
        DealClientData(c);
        // 关闭客户端通信套接字
        close(c);
    }
    exit(0);
}

3 运行说明

(1)环境准备

在代码同级目录创建index.html (首页内容)和 404.html (404错误页面)

确保Linux环境下安装gcc编译器

(2)编译代码
bash 复制代码
 gcc http_server.c -o http_server
(3)运行服务器
bash 复制代码
 ./http_server
(4)测试访问

浏览器访问 http://127.0.0.1 ,可查看 index.html内容

访问不存在的文件(如 http://127.0.0.1/test.html ),将显示 404.html内容

相关推荐
南行*4 小时前
C语言Linux环境编程
linux·c语言·开发语言·网络安全
June`4 小时前
IO模型全解析:从阻塞到异步(高并发的reactor模型)
linux·服务器·网络·c++
ASS-ASH4 小时前
快速处理虚拟机磁盘扩容问题
linux·数据库·vmware·虚拟机·磁盘扩容
AI_56784 小时前
零基础学Linux:21天从“命令小白”到独立部署服务器
linux·服务器·人工智能·github
江湖有缘4 小时前
Fenrus + Docker 实战:构建简洁高效的浏览器新标签页
运维·docker·容器
乾元4 小时前
如何把 CCIE / HCIE 的实验案例改造成 AI 驱动的工程项目——从“实验室能力”到“可交付系统”的完整迁移路径
大数据·运维·网络·人工智能·深度学习·安全·机器学习
不染尘.4 小时前
Linux基本概述
linux·windows·centos·ssh
lpfasd1234 小时前
宝塔面板(BT Panel)集成雷池 SafeLine WAF(社区版)
运维
weixin_446260854 小时前
XPipe: 轻松访问你的服务器基础设施 [特殊字符]
运维·服务器