linux学习笔记(33)网络编程——HTTP协议
HTTP 超文本传输协议
它到传输层只用tcp
浏览器与服务器通信过程
浏览器与 web 服务器在应用层通信使用的是 HTTP 协议(超文本传输协议),而 HTTP协议在传输层使用的是 TCP 协议。那么浏览器需要和 web 服务器三次握手建立连接后,才
可以发送 HTTP 请求报文,服务器收到请求报文后,向浏览器回复 HTTP 应答报文。
浏览器向服务器发起连接前,需要得到服务器的 IP 及端口。用户在浏览器中通常只输入网址(网站域名),浏览器会通过 DNS 服务查询获取到服务器的 IP 地址。对于端口来讲,
使用 HTTP 协议的程序一般默认使用 80 端口。
浏览器服务器建立连接后,如果两次以上的请求复用同一个 TCP 连接,则称之为长连接。
如果浏览器发送一次请求报文,服务器回复一次应答就断开连接,下次交互再重新进行三次握手建立连接,那么就被称作短连接。
使用长连接显然是更好一些,可以减少网络中的同步报文,也使得服务器的响应速度变快。
常见的 web 服务器有:
◼ Apache: 简单、速度快、性能稳定,并可做代理服务器使用
◼ IIS(Internet Information Server):安全性、强大、灵活
◼ Nginx:小巧而高效,可以做高效的负载均衡反向代理
◼ Tomcat:技术先进、性能稳定、免费


HTTP方法(常用的)
GET - 获取资源:
GET /users/123 HTTP/1.1
Host: api.example.com
像说: "给我用户123的信息"
POST - 创建资源:
POST /users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 45{"name":"张三","email":"zhang@example.com"}
像说: "创建一个新用户,这是用户信息"
PUT - 更新资源:
PUT /users/123 HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 47{"name":"李四","email":"li@example.com"}
像说: "把用户123的信息更新成这个"
DELETE - 删除资源:
DELETE /users/123 HTTP/1.1
Host: api.example.com
像说: "删除用户123"
HTTP状态码
常见状态码:
// 2xx 成功
200 OK // 请求成功
201 Created // 创建成功// 3xx 重定向
301 Moved Permanently // 永久重定向
302 Found // 临时重定向// 4xx 客户端错误
400 Bad Request // 请求格式错误
401 Unauthorized // 未认证
403 Forbidden // 禁止访问
404 Not Found // 找不到页面// 5xx 服务器错误
500 Internal Server Error // 服务器内部错误
502 Bad Gateway // 网关错误
HTTP头部字段
常用请求头:
GET / HTTP/1.1
Host: www.example.com // 目标域名
User-Agent: Mozilla/5.0 // 浏览器信息
Accept: text/html // 可接受的类型
Accept-Language: zh-CN // 语言偏好
Cookie: session=abc123 // Cookie数据
常用响应头:
HTTP/1.1 200 OK
Content-Type: text/html // 内容类型
Content-Length: 1024 // 内容长度
Set-Cookie: session=xyz789 // 设置Cookie
Cache-Control: max-age=3600 // 缓存控制
我来给你写一个最简单的HTTP服务器,就叫myhttp!
1. 最简版的myhttp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>#define PORT 8080
#define BUFFER_SIZE 4096// 发送HTTP响应
void send_response(int client_fd, const char* content) {char response[BUFFER_SIZE];snprintf(response, sizeof(response),"HTTP/1.1 200 OK\r\n""Content-Type: text/html\r\n""Content-Length: %zu\r\n""Connection: close\r\n""\r\n""%s", strlen(content), content);write(client_fd, response, strlen(response));
}int main() {printf("🚀 MyHTTP 服务器启动!\n");printf("📡 访问: http://localhost:%d\n", PORT);// 创建TCP socketint server_fd = socket(AF_INET, SOCK_STREAM, 0);// 设置端口重用int opt = 1;setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));// 绑定地址struct sockaddr_in address;address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);bind(server_fd, (struct sockaddr*)&address, sizeof(address));listen(server_fd, 5);printf("✅ 服务器准备就绪,等待连接...\n\n");while (1) {// 接受客户端连接int client_fd = accept(server_fd, NULL, NULL);char buffer[BUFFER_SIZE];int bytes_read = read(client_fd, buffer, sizeof(buffer) - 1);if (bytes_read > 0) {buffer[bytes_read] = '\0';// 打印请求信息(前200字符)printf("📨 收到请求:\n%.200s\n", buffer);// 简单的路由处理if (strstr(buffer, "GET /hello ")) {char* html = "<html>""<body style='font-family: Arial; padding: 20px;'>""<h1>👋 你好!</h1>""<p>这是我的MyHTTP服务器!</p>""<p><a href='/time'>查看时间</a></p>""<p><a href='/about'>关于</a></p>""</body>""</html>";send_response(client_fd, html);}else if (strstr(buffer, "GET /time ")) {char* html = "<html>""<body style='font-family: Arial; padding: 20px;'>""<h1>⏰ 当前时间</h1>""<p>2024年1月1日 12:00:00</p>""<p><a href='/hello'>返回首页</a></p>""</body>""</html>";send_response(client_fd, html);}else if (strstr(buffer, "GET /about ")) {char* html = "<html>""<body style='font-family: Arial; padding: 20px;'>""<h1>ℹ️ 关于MyHTTP</h1>""<p>这是一个用C语言编写的简单HTTP服务器</p>""<p>支持多页面浏览!</p>""<p><a href='/hello'>返回首页</a></p>""</body>""</html>";send_response(client_fd, html);}else {// 默认页面char* html = "<html>""<body style='font-family: Arial; padding: 20px;'>""<h1>🌐 MyHTTP 服务器</h1>""<p>欢迎使用我的HTTP服务器!</p>""<ul>""<li><a href='/hello'>欢迎页面</a></li>""<li><a href='/time'>时间页面</a></li>""<li><a href='/about'>关于页面</a></li>""</ul>""</body>""</html>";send_response(client_fd, html);}}close(client_fd);}close(server_fd);return 0;
}
2. 编译和运行
编译:
gcc -o myhttp myhttp.c
运行:
./myhttp
3. 测试你的MyHTTP服务器
方法1:用浏览器访问
打开浏览器,访问这些网址:
http://localhost:8080
http://localhost:8080/hello
http://localhost:8080/time
http://localhost:8080/about
方法2:用curl命令测试
curl http://localhost:8080
curl http://localhost:8080/hello
curl http://localhost:8080/time
4. 增强版:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8080
#define BUFFER_SIZE 1024
// 发送HTML页面
void send_html(int client_fd, char* title, char* content) {char response[BUFFER_SIZE];snprintf(response, sizeof(response),"HTTP/1.1 200 OK\r\n""Content-Type: text/html\r\n""\r\n" // 空行分隔头部和内容"<html><body><h1>%s</h1><p>%s</p></body></html>",title, content);write(client_fd, response, strlen(response));
}// 发送404错误页面
void send_404(int client_fd) {char* response ="HTTP/1.1 404 Not Found\r\n""Content-Type: text/html\r\n""\r\n""<html><body><h1>404 页面未找到</h1></body></html>";write(client_fd, response, strlen(response));
}int main() {printf("🚀 HTTP服务器启动: http://localhost:%d\n", PORT);// 1. 创建socketint server_fd = socket(AF_INET, SOCK_STREAM, 0);// 2. 设置地址和端口struct sockaddr_in address = {.sin_family = AF_INET,.sin_addr.s_addr = INADDR_ANY, // 监听所有网卡.sin_port = htons(PORT) // 端口号};// 3. 绑定端口bind(server_fd, (struct sockaddr*)&address, sizeof(address));// 4. 开始监听listen(server_fd, 5);printf("✅ 服务器准备就绪!\n\n");// 主循环:处理客户端请求while (1) {// 5. 接受客户端连接int client_fd = accept(server_fd, NULL, NULL);char buffer[BUFFER_SIZE];int bytes = read(client_fd, buffer, sizeof(buffer) - 1);if (bytes > 0) {buffer[bytes] = '\0';// 6. 根据请求路径返回不同内容if (strstr(buffer, "GET / ")) {send_html(client_fd, "首页", "欢迎访问我的网站!");}else if (strstr(buffer, "GET /hello ")) {send_html(client_fd, "Hello页面", "你好!这是一个示例页面。");}else if (strstr(buffer, "GET /about ")) {send_html(client_fd, "关于", "这是一个简单的HTTP服务器");}else {send_404(client_fd); // 其他路径返回404}}// 7. 关闭连接close(client_fd);}close(server_fd);return 0;
}
5. 创建测试HTML文件
创建一个index.html文件来测试文件服务功能:
<!DOCTYPE html>
<html>
<head><title>MyHTTP 服务器</title><style>body { font-family: Arial; padding: 40px; background: #f0f0f0; }.container { max-width: 800px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; }h1 { color: #333; }a { color: #007bff; text-decoration: none; }a:hover { text-decoration: underline; }</style>
</head>
<body><div class="container"><h1>🎉 欢迎使用 MyHTTP!</h1><p>这是一个用C语言编写的HTTP服务器</p><h2>📚 可用页面:</h2><ul><li><a href="/hello">Hello 页面</a></li><li><a href="/time">时间页面</a></li><li><a href="/about">关于页面</a></li></ul><h2>⚡ 特性:</h2><ul><li>支持HTTP/1.1协议</li><li>多页面路由</li><li>静态文件服务</li><li>错误处理</li></ul></div>
</body>
</html>
6. 项目结构
myhttp/
├── myhttp.c # 主程序
├── index.html # 主页文件
└── README.md # 说明文档
你的MyHTTP服务器现在可以:
- ✅ 处理HTTP请求
- ✅ 支持多个页面路由
- ✅ 返回HTML内容
- ✅ 处理404错误
- ✅ 服务静态文件
现在你有一个真正可用的HTTP服务器了!可以继续添加更多功能,比如POST处理、JSON API、文件上传等。🚀