HTTP协议与服务器实现详解
2026/5/8 10:50:42 网站建设 项目流程

引言

在学习了TCP协议编程之后,我们已经能够实现客户端和服务器之间的基本通信。然而,真正的互联网应用大多使用的是更高级的协议——HTTP协议

HTTP(HyperText Transfer Protocol,超文本传输协议)是互联网上应用最广泛的协议之一。当你在浏览器中输入网址并回车时,浏览器与服务器之间就是通过HTTP协议进行通信的。

第一部分:HTTP协议基础

一、HTTP协议的特点

特性说明
应用层协议位于OSI模型的应用层
基于TCPHTTP协议在传输层使用TCP协议(默认端口80)
请求-响应模型客户端发起请求,服务器返回响应
无状态协议每个请求之间相互独立(Cookie解决状态问题)

二、HTTP请求方法

方法说明安全性典型场景
GET请求获取资源安全(只读)浏览网页、下载文件
POST提交数据不安全(修改服务器状态)表单提交、登录注册
PUT上传资源不安全文件上传
DELETE删除资源不安全删除数据
HEAD只请求头部安全检查资源是否存在
OPTIONS查询支持的方法安全CORS预检请求

重点掌握GET与POST的区别:

对比项GETPOST
作用获取资源提交数据
数据位置URL中请求体中
数据长度限制有(浏览器限制)
幂等性
缓存可缓存不可缓存

三、HTTP请求报文结构

GET /index.html HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1

请求报文结构:

四、HTTP响应报文结构

HTTP/1.1 200 OK
Server: my_http_server
Content-Type: text/html
Content-Length: 127

<html>
<head><title>Test</title></head>
<body>Hello World</body>
</html>

响应报文结构:

五、HTTP状态码

分类含义典型状态码
1xx信息类100 Continue(继续发送)
2xx成功类200 OK(请求成功)
3xx重定向类301(永久重定向)、302(临时重定向)、304(未修改)
4xx客户端错误400(错误请求)、401(未授权)、403(禁止)、404(未找到)
5xx服务器错误500(内部错误)、503(服务不可用)

第二部分:HTTP服务器的实现

一、核心功能概述

我们要实现的HTTP服务器具备以下功能:

  1. 监听80端口(HTTP默认端口)

  2. 接收浏览器的HTTP请求

  3. 解析请求报文,获取请求的文件名

  4. 在本地查找文件

  5. 如果文件存在,返回200 OK和文件内容

  6. 如果文件不存在,返回404 Not Found

二、基础TCP服务器框架

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #define PORT 80 #define BUFFER_SIZE 1024 #define FILE_BUFFER_SIZE 512 #define WEB_ROOT "/home/user/mycode/http" // 网站根目录 // 创建并初始化套接字 int init_socket() { // 1. 创建套接字 int sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (sock_fd == -1) { perror("socket error"); return -1; } // 2. 设置端口复用(解决TIME_WAIT问题) int opt = 1; setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); // 3. 绑定地址和端口 struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) { perror("bind error"); close(sock_fd); return -1; } // 4. 监听 if (listen(sock_fd, 5) == -1) { perror("listen error"); close(sock_fd); return -1; } printf("HTTP服务器启动成功,端口:%d\n", PORT); return sock_fd; }

三、解析请求获取文件名

// 从HTTP请求报文中提取请求的文件名 char* get_filename(char* buffer) { // 按空格分割请求行 char* method = strtok(buffer, " "); if (method == NULL) return NULL; // 获取请求的URL(如 /index.html 或 /) char* url = strtok(NULL, " "); if (url == NULL) return NULL; // 如果请求的是根路径(/),返回默认首页 if (strcmp(url, "/") == 0) { return "index.html"; } // 去掉开头的斜杠,返回相对路径 return url + 1; }

四、打开文件并获取文件大小

// 打开文件并获取文件大小 int open_file(const char* filename, off_t* file_size) { if (filename == NULL || file_size == NULL) return -1; // 拼接完整路径 char fullpath[256]; snprintf(fullpath, sizeof(fullpath), "%s/%s", WEB_ROOT, filename); // 打开文件 int fd = open(fullpath, O_RDONLY); if (fd == -1) { printf("文件不存在: %s\n", fullpath); return -1; } // 获取文件大小 struct stat st; if (stat(fullpath, &st) == -1) { close(fd); return -1; } *file_size = st.st_size; return fd; }

五、发送HTTP响应头

// 发送200 OK响应头 void send_http_header(int client_fd, off_t file_size) { char header[512]; // 状态行 snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n" "Server: my_http_server\r\n" "Content-Type: text/html\r\n" "Content-Length: %ld\r\n" "\r\n", file_size); send(client_fd, header, strlen(header), 0); } // 发送404 Not Found响应头 void send_404_header(int client_fd) { const char* header = "HTTP/1.1 404 Not Found\r\n" "Server: my_http_server\r\n" "Content-Type: text/html\r\n" "Content-Length: 58\r\n" "\r\n" "<html><body><h1>404 Not Found</h1></body></html>"; send(client_fd, header, strlen(header), 0); }

六、发送文件内容

// 发送文件内容 void send_file_content(int client_fd, int file_fd) { char buffer[FILE_BUFFER_SIZE]; ssize_t n; while ((n = read(file_fd, buffer, FILE_BUFFER_SIZE)) > 0) { send(client_fd, buffer, n, 0); } }

七、主函数

int main() { int listen_fd = init_socket(); if (listen_fd == -1) { exit(1); } while (1) { // 接受客户端连接 int client_fd = accept(listen_fd, NULL, NULL); if (client_fd == -1) { perror("accept error"); continue; } // 接收HTTP请求 char buffer[BUFFER_SIZE]; memset(buffer, 0, BUFFER_SIZE); int n = recv(client_fd, buffer, BUFFER_SIZE - 1, 0); if (n > 0) { printf("收到请求:\n%s\n", buffer); // 解析请求,获取文件名 char* filename = get_filename(buffer); printf("请求文件: %s\n", filename ? filename : "(null)"); // 打开文件并获取大小 off_t file_size; int file_fd = open_file(filename, &file_size); if (file_fd == -1) { // 文件不存在,发送404 send_404_header(client_fd); } else { // 文件存在,发送200 OK和文件内容 send_http_header(client_fd, file_size); send_file_content(client_fd, file_fd); close(file_fd); } } // 关闭连接(短连接) close(client_fd); } close(listen_fd); return 0; }

第三部分:编译与运行

一、编译注意事项

# 80端口需要管理员权限
sudo gcc http_server.c -o http_server

# 运行
sudo ./http_server

二、测试

  1. 启动服务器后,打开浏览器

  2. 访问http://127.0.0.1/

  3. 服务器会返回index.html文件

  4. 访问http://127.0.0.1/test.html(如果文件存在)


第四部分:HTML基础知识

一、HTML基本结构

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>页面标题</title> </head> <body> <h1>一级标题</h1> <p>这是一个段落。</p> <img src="image.jpg" alt="图片"> <a href="next.html">下一页</a> </body> </html>

二、常用HTML标签

标签作用
<h1>-<h6>标题
<p>段落
<a>超链接
<img>图片
<div>区块容器
<span>内联容器
<ul><li>列表
<table>表格

第五部分:HTTP长短连接

一、短连接

  • 每次请求都建立新的TCP连接

  • 请求结束后立即关闭连接

  • 适用于请求频率较低的场景

二、长连接

  • 多次请求复用同一个TCP连接

  • 通过Connection: keep-alive头部声明

  • 减少连接建立的开销,提高效率

// 长连接示例:循环处理同一个客户端的多个请求 while (1) { memset(buffer, 0, BUFFER_SIZE); int n = recv(client_fd, buffer, BUFFER_SIZE - 1, 0); if (n <= 0) break; // 客户端关闭连接 // 处理请求... // 不关闭连接,继续处理下一个请求 }

总结

一、HTTP核心知识点

知识点说明
端口默认80端口
请求方法GET(获取)、POST(提交)
状态码200(成功)、404(未找到)、500(服务器错误)
请求结构请求行、请求头、空行、请求体
响应结构状态行、响应头、空行、响应体
长短连接Connection头部控制

二、实现HTTP服务器的关键步骤

  1. 创建TCP服务器,监听80端口

  2. 接收客户端连接

  3. 读取HTTP请求报文

  4. 解析请求行,获取请求的文件名

  5. 在本地查找文件

  6. 组装HTTP响应报文

  7. 发送响应头和文件内容

  8. 关闭连接(短连接)或保持连接(长连接)

本文从一个简单的HTTP服务器实现入手,深入讲解了HTTP协议的基本原理。理解HTTP协议不仅有助于网络编程,更是Web开发的基础。

学习建议:

  1. 动手实现HTTP服务器,观察浏览器请求的原始报文

  2. 理解GET和POST的区别

  3. 掌握常见状态码的含义

  4. 学习HTML基础知识,理解网页的构成

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询