【Linux】网络之http协议

作者:爱吃生蚝的于勒日期:2026/3/24

文章目录

  • URL
  • 🚩HTTP协议格式
    • 请求格式
      • HTTP常用方法
    • 响应格式
      • 常见状态码
        • HTTP常见Header
  • 🚩模拟实现HTTP服务器
    • ⭐Cookie

URL

我们所说的网址就是URL
在这里插入图片描述
如果在参数中出现?/特殊字符,会自动转义,/ ?字符已经被url特殊处理了
在这里插入图片描述
‘+’被转义为%2b

🚩HTTP协议格式

请求格式

在这里插入图片描述
请求行:方法+URL+版本号+\r\n
请求报头:每行一对键值对+\r\n
\r\n空行,(没有空行的话无法区分报头和正文)
正文,(怎么确定正文的大小?报头中content-length确定)

例如
在这里插入图片描述

HTTP常用方法

在这里插入图片描述
常用的就GET,POST

响应格式

在这里插入图片描述
与请求类似,
在这里插入图片描述

常见状态码

在这里插入图片描述
常用状态码:200(OK),404 (Not Found),403 (Forbidden),302(Redirect,重定向(跳转网站)),504(Bad Gateway)

HTTP常见Header

Content-Type: 数据类型(text/html等)
Content-Length: Body的长度
Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
User-Agent: 声明用户的操作系统和浏览器版本信息;
referer: 当前页面是从哪个页面跳转过来的;
location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;

🚩模拟实现HTTP服务器

目录结构
在这里插入图片描述

1//socket.hpp
2#pragma once
3
4#include <iostream>
5#include <sys/types.h>
6#include <sys/socket.h>
7#include <arpa/inet.h>
8#include "log.hpp"
9#include <string.h>
10#include <unistd.h>
11using namespace std;
12
13Log lg;
14const int backlog=10;
15
16enum{
17    SocketErr=2,
18    BindErr,
19    ListenErr,
20};
21
22class Sock{
23public:
24    Sock()
25    {}
26    ~Sock()
27    {}
28
29    void Socket()
30    {
31        sockfd_=socket(AF_INET,SOCK_STREAM,0);
32        if(sockfd_<0)
33        {
34            lg(Fatal,"socket error, strerror: %s, errno: %d",strerror(errno),errno);
35            exit(SocketErr);
36        }
37    }
38    void Bind(uint16_t port)
39    {
40        struct sockaddr_in local;
41        memset(&local,0,sizeof(local));
42        local.sin_family=AF_INET;
43        local.sin_port=htons(port);
44        local.sin_addr.s_addr=INADDR_ANY;
45
46        if(bind(sockfd_,(struct sockaddr*)&local,sizeof(local))<0)
47        {
48            lg(Fatal,"Bind error, strerror: %s, errno: %d",strerror(errno),errno);
49            exit(BindErr);
50        }
51
52    }
53    void Listen()
54    {
55        if(listen(sockfd_,backlog)<0)
56        {
57            lg(Fatal,"Listen Error, strerror: %s, errno: %d",strerror(errno),errno);
58            exit(ListenErr);
59        }
60    }
61    int Accept(std::string* ip,uint16_t *port)
62    {
63        struct sockaddr_in peer;
64        socklen_t len=sizeof(peer);
65        int newfd=accept(sockfd_,(struct sockaddr*)&peer,&len);
66        if(newfd<0)
67        {
68            lg(Warning,"accept error, strerror: %s, errno: %d",strerror(errno),errno);
69            return -1;
70        }
71        char ipstr[64];
72        inet_ntop(AF_INET,&peer.sin_addr,ipstr,sizeof(ipstr));
73        *ip=ipstr;
74        *port=ntohs(peer.sin_port);
75        
76        return newfd;
77    }
78    bool Connect(const string& ip,const uint16_t& port)
79    {
80        struct sockaddr_in peer;
81        memset(&peer,0,sizeof(peer));
82        peer.sin_family=AF_INET;
83        peer.sin_port=htons(port);
84        inet_pton(AF_INET,ip.c_str(),&(peer.sin_addr));
85
86        int n=connect(sockfd_,(struct sockaddr*)&peer,sizeof(peer));
87        if(n<0)
88        {
89            cerr<<"Connect to"<<ip<<":"<<port<<endl;
90            return false;
91        }
92        return true;
93    }
94    void Close()
95    {
96        close(sockfd_);
97    }
98    int Fd()
99    {
100        return sockfd_;
101    }
102private:
103    int sockfd_;
104};
105
106//server.hpp
107#pragma once
108#include <iostream>
109#include "Socket.hpp"
110#include <string>
111#include <pthread.h>
112#include <fstream>
113#include <vector>
114#include <sstream>
115#include <sys/types.h>
116#include <sys/socket.h>
117#include <unordered_map>
118
119std::string blank_line="\r\n";
120std::string wwwroot="./wwwroot";
121std::string homepage="index.html";
122
123class HttpServer;
124
125class ThreadData
126{
127public:
128    ThreadData(int sockfd,HttpServer* hs)
129    :_sockfd(sockfd),_hs(hs)
130    {
131
132    }
133public:
134    int _sockfd;
135    HttpServer* _hs;
136};
137
138class HttpResponse
139{
140public:
141    void Derialize(std::string req)
142    {
143        while(true)
144        {
145            std::size_t pos=req.find(blank_line);
146            if(pos==string::npos)break;
147            std::string temp=req.substr(0,pos);
148            if(temp.empty())//空行
149            break;
150            vc.push_back(temp);
151            req.erase(0,pos+blank_line.size());
152        }
153        text+=req;
154        
155    }
156    void Parse()
157    {
158        std::stringstream ss(vc[0]);
159        ss>>method>>url>>version;
160        
161        file_path=wwwroot;
162        if(url=="/"||url=="index.html")
163        {
164            file_path+="/";
165            file_path+=homepage; //wwwroot/index.html
166        }
167        else{
168            file_path+=url; //wwwroot/a/b/t/t
169        }
170    }
171    void Dubugprint()
172    {
173        for(auto line:vc)
174        {
175            std::cout<<line<<std::endl;
176            std::cout<<"------------"<<std::endl;
177        }
178        std::cout<<"method: "<<method<<std::endl;
179        std::cout<<"url: "<<url<<std::endl;
180        std::cout<<"version: "<<version<<std::endl;
181        std::cout<<"file_path: "<<file_path<<std::endl;
182        std::cout<<"text: "<<text<<std::endl;
183    }   
184public:
185    vector<string> vc;
186    string text;
187
188    std::string method;
189    std::string url;
190    std::string version;
191
192    std::string file_path;
193};
194
195class HttpServer
196{
197public:
198    HttpServer(uint16_t port)
199    :_port(port)
200    {
201
202    }
203    void start()
204    {
205        _listen.Socket();
206        _listen.Bind(_port);
207        _listen.Listen();
208        lg(Info,"server create success");
209        for(;;)
210        {
211            std::string clientip;
212            uint16_t port;
213            int sockfd=_listen.Accept(&clientip,&port);
214            lg(Info,"get a newfd:%d",sockfd);
215            pthread_t tid;
216            ThreadData* td=new ThreadData(sockfd,this);
217            pthread_create(&tid,nullptr,ThreadRun,td);
218        }
219    }
220    static std::string ReadHtmlContent(const std::string& htmlpath)
221    {
222        std::ifstream in(htmlpath);
223        if(!in.is_open())
224        {
225            return "404";
226        }
227        std::string content;
228        std::string line;
229        while(getline(in,line))
230        {
231            content+=line;
232        }
233        in.close();
234        return content;
235    }
236    static void HandlerHttp(int sockfd)
237    {
238        char buffer[10240];
239        ssize_t n=recv(sockfd,buffer,sizeof(buffer)-1,0);
240        if(n>0)
241        {
242            buffer[n]=0;
243            //std::cout<<buffer<<endl;
244            //返回响应过程
245           
246
247            HttpResponse rep;
248            rep.Derialize(buffer);
249            rep.Parse();
250            rep.Dubugprint();
251
252            std::string text=ReadHtmlContent(rep.file_path);
253            
254            std::string response_line="HTTP/1.0 299 OK\r\n";
255            std::string response_header ="Content-Length: ";
256            response_header+=std::to_string(text.size()); //"Content-length: 11"
257
258            std::string response=response_line;
259            response+=response_header; 
260            response+="\r\n";
261            response += blank_line;
262
263            response+=text;
264            send(sockfd,response.c_str(),response.size(),0);
265        }
266        close(sockfd);
267    }
268    static void *ThreadRun(void* args)
269    {
270        pthread_detach(pthread_self());
271        ThreadData* td=static_cast<ThreadData*>(args);
272
273        HandlerHttp(td->_sockfd);
274        
275        close(td->_sockfd);
276        delete td;
277        return nullptr;
278    }
279Sock _listen;
280uint16_t _port;
281
282//index.html
283<!DOCTYPE html>
284<html lang="en">
285<head>
286    <meta charset="UTF-8">
287    <meta name="viewport" content="width=device-width, initial-scale=1.0">
288    <title>Document</title>
289</head>
290<body>
291    <h1>这个是我们的首页</h1>
292
293
294    <a href="http://115.175.6.15:8080/a/b/hello.html">到第二张网页</a>
295
296    <a href="http://115.175.6.15:8080/c/d/hello2.html">到第三张网页</a>
297</body>
298</html>
299};
300
301//hello.html
302<!DOCTYPE html>
303<html lang="en">
304<head>
305    <meta charset="UTF-8">
306    <meta name="viewport" content="width=device-width, initial-scale=1.0">
307    <title>Document</title>
308</head>
309<body>
310    <h1>第二张图片</h1>
311    <h1>第二张图片</h1>
312    <h1>第二张图片</h1>
313
314    <a href="http://115.175.6.15:8080">回到首页</a>
315
316    <a href="http://115.175.6.15:8080/c/d/hello2.html">到第三张网页</a>
317</body>
318</html>
319//hello2.html
320<!DOCTYPE html>
321<html lang="en">
322<head>
323    <meta charset="UTF-8">
324    <meta name="viewport" content="width=device-width, initial-scale=1.0">
325    <title>Document</title>
326</head>
327<body>
328    <h1>第三张图片</h1>
329
330    <a href="http://115.175.6.15:8080">回到首页</a>
331
332    <a href="http://115.175.6.15:8080/a/b/hello.html">到第三张网页</a>
333</body>
334</html>
335
336
337//Log.hpp
338#pragma once
339#include <iostream>
340#include <stdlib.h>
341#include <time.h>
342#include <stdarg.h>
343#include <string.h>
344#include <sys/types.h>
345#include <sys/stat.h>
346#include <fcntl.h>
347#include <unistd.h>
348
349using namespace std;
350#define SIZE 1024
351
352#define Info 0
353#define Debug 1
354#define Warning 2
355#define Error 3
356#define Fatal 4
357
358#define Screen    1
359#define Onefile   2
360#define Classfile 3
361
362#define Logfile "log.txt"
363class Log{
364public:
365    Log()
366    {
367        printmethod=Screen;
368        path="./log/";
369        mkdir(path.c_str(), 0777);
370    }
371    void Enable(int method)
372    {
373        printmethod=method;
374    }
375    string levelToString(int level)
376    {
377         switch(level)
378        {
379            case Info:
380            return "Info";
381            case Debug:
382            return "Debug";
383            case Warning:
384            return "Warning";
385            case Error:
386            return "Error";
387            case Fatal:
388            return "Fatal";
389       }
390    }
391/*
392void logmassage(int level,char* format, ...)
393{
394    time_t t=time(nullptr);
395    struct tm *ctime = localtime(&t);
396    char leftbuffer[SIZE];
397    snprintf(leftbuffer,sizeof(leftbuffer),"[%s][%d-%d-%d %d %d %d]",levelToString(level).c_str(),ctime->tm_year+1900,ctime->tm_mon+1,ctime->tm_mday,ctime->tm_min,ctime->tm_sec);
398
399    va_list(s);
400    va_start(s,format);
401
402    char rightbuffer[SIZE];
403    vsnprintf(rightbuffer,sizeof(rightbuffer),format,s);
404    va_end(s);
405
406    char logtxt[SIZE*2];
407    snprintf(logtxt,sizeof(logtxt),"%s %s\n",leftbuffer,rightbuffer);
408
409    printf("%s\n",logtxt);
410
411}*/
412    void operator()(int level,const char* format, ...)
413    {
414    time_t t=time(nullptr);
415    struct tm *ctime = localtime(&t);
416    char leftbuffer[SIZE];
417    snprintf(leftbuffer,sizeof(leftbuffer),"[%s][%d-%d-%d %d %d %d]",levelToString(level).c_str(),ctime->tm_year+1900,ctime->tm_mon+1,ctime->tm_mday,ctime->tm_hour,ctime->tm_min,ctime->tm_sec);
418
419    va_list(s);
420    va_start(s,format);
421
422    char rightbuffer[SIZE];
423    vsnprintf(rightbuffer,sizeof(rightbuffer),format,s);
424    va_end(s);
425
426    char logtxt[SIZE*2];
427    snprintf(logtxt,sizeof(logtxt),"%s %s",leftbuffer,rightbuffer);
428
429    //printf("%s\n",logtxt);
430    printlog(level,logtxt);
431    }
432    void printlog(int level,const string& logtxt)
433    {
434        switch(printmethod)
435        {
436            case Screen:
437            cout<<logtxt<<endl;
438            break;
439            case Onefile:
440            printOnefile(Logfile,logtxt);
441            break;
442            case Classfile:
443            printClassfile(level,logtxt);
444            break;
445        }
446    }
447    void printOnefile(const string& failname,const string& logtxt)
448    {
449        string _failname = path + failname;
450        int fd=open(_failname.c_str(),O_WRONLY|O_CREAT|O_APPEND,0666);
451        if(fd<0)
452        {
453            return;
454        }
455        write(fd,logtxt.c_str(),logtxt.size());
456        close(fd);
457    }
458    void printClassfile(int level,const string& logtxt)
459    {
460        string _failname=Logfile;
461        _failname += ".";
462        _failname += levelToString(level);
463        printOnefile(_failname,logtxt); 
464    }
465    ~Log()
466    {}
467private:
468    int printmethod;
469    string path;
470
471};
472
473//server.cc
474#include <iostream>
475#include "HttpServer.hpp"
476using namespace std;
477int main(int argc,char* argv[])
478{
479    if(argc!=2)
480    {
481        exit(1);
482    }
483    HttpServer* svr=new HttpServer(stoi(argv[1]));
484    svr->start();
485    return 0;
486}
487

启动服务端
在这里插入图片描述
打开浏览器输入 ip:端口号
在这里插入图片描述
实现成功,点击第二张网页

在这里插入图片描述
xhell查看浏览器发送的请求

在这里插入图片描述
我们可以看到域名也发生了变化,其实就是跳转到特定的文件
在这里插入图片描述

⭐Cookie

为什么我们第一次访问b站要登陆账户,但是第二次就不需要再登陆了?
:因为浏览器帮我们记住账户了,账户信息存储在Cookie中,此外,服务器为我们分配了ID=,我们每次访问b站视频==,浏览器都会带着Cookie和ID让服务器确认账号信息

Cookie信息在浏览器左上角,如果我们删除Cookie就会让我们再次输入账户信息
在这里插入图片描述
客户端第一次向服务端发送账号和密码,服务器为客户端建立Cookie并分配ID,之后客户端每次访问服务端都带着Cookie和ID,服务端在数据库查找确认

在我们服务器代码加入Cookie报头

1 response_header+="Set-Cookie: name=haha&&passward=123456";
2 response_header+="\r\n";
3

左上角打开我们的浏览器Cookie信息
在这里插入图片描述


【Linux】网络之http协议》 是转载文章,点击查看原文


相关推荐


C++入门基础
全球便秘冠军保持者2026/3/16

C++的第一个程序 #include<stdio.h> int main() { printf("Hello World!\n"); return 0; } 这是我们使用的c++的编译器写的c语言的“Hello World!”,说明c++的编译器可以兼容c语言的语法 那我们来看一下用c++写的“Hello World!” #include <iostream> using namespace std; int main() { cout << "Hello World!"


拒绝写重复代码,试试这套开源的 SpringBoot 组件,效率翻倍~
皮皮林5512026/3/7

目录 1 简介 2 快速入门 2.1 Spring Boot 接口开发现状 2.2 快速入门 1 简介 Graceful Response 是一个 Spring Boot 技术栈下的优雅响应处理器,提供一站式统一返回值封装、全局异常处理、自定义异常错误码 等功能,使用 Graceful Response 进行 web 接口开发不仅可以节省大量的时间,还可以提高代码质量,使代码逻辑更清晰。 强烈推荐你花 3 分钟学会它! 本项目案例工程代码:https://github.com/fe


程序员的明天:AI 时代下的行业观察与个人思考
勇哥Java实战2026/2/27

这篇文章分享了我对 AI 时代下,软件行业发展以及程序员命运走向的 5 点思考,供大家参考。 1 匠人时代落幕 Redis 之父 antirez,最近写了一篇文章 《 Don't fall into the anti-AI hype 》,读完之后,我深有感触。 文章的观点非常明确: AI 不仅改变了编码方式,更重塑了软件行业的价值结构和职业路径,程序员需要从“手动编码”转向“设计系统与与 AI 协作” 。 过去的软件行业,其实有一种很典型的“匠人红利”。谁代码写得更优雅,谁框架更熟,谁对某个


QT & QML 总结备查
瞰百2026/2/19

QT & QML 总结备查 首要注意,在桌面端开发QT可免费商用,而嵌入式端QT商用则收费。 各种 UI 库的总结和对比: Cpp-Learning/C-C++实用库备查.md at main · Staok/Cpp-Learning。 文章所在 Github 仓库 Staok/QT-QML-Learning: QT & QML 总结备查文章 会保持最新,其它地方的不会跟进。 常看常新 QT 安装:网搜 Qt Creator 下载和安装即可。 编译器:对于 Win 上


英语语法笔记:英语不应该成为开发工程师的发展瓶颈
修己xj2026/2/11

前几天,是公司成立二十周年的年会。老板作了一场题为《穿越寒冬,求实存善》的演讲。那一刻我在想:当寒意渐浓,作为领航者,他思考的是如何带领公司扛过这场冬天;那作为程序员的我们,又该如何穿越自己的寒冬呢? Vue 作者尤雨溪曾坦言:“不仅英语差会成为瓶颈,英语好还能成为优势,因为学习效率会比别人高。像我这样半路出家自学的人,只能靠英语了……”确实,无论是阅读技术文档、参与开源社区、在 Stack Overflow 寻找答案,还是追踪最新技术资讯、争取一份远程机会,英语早已不是可选项,而是必修课——是


AI - 通过 Docker 来安装与访问 OpenClaw
LinXunFeng2026/2/2

欢迎关注微信公众号:FSA全栈行动 👋 一、简介 这是我在 Mac 上通过 Docker 来安装和配置 OpenClaw 的一份记录,随着文章从上到下一步步做就可以了。 二、docker 拉取 Ubuntu 镜像 docker pull ubuntu:latest 创建容器 创建容器,并映射 18789 端口 docker run -it -p 18789:18789 --name openclaw ubuntu 搭配 Docker 容器的分离快捷键,先按 Ctrl+P,再按 Ctrl+


🚀 纯前端离线局域网P2P大文件断点传输:别让你的照片墙崩了
子兮曰2026/1/23

前言:小明和他的照片墙危机 想象一下,你是小明,一个热爱摄影的程序员。周末去爬山拍了一堆4K高清照片,总共3GB,准备发给老婆分享。微信传?算了,压缩后画质渣得像像素风。网盘?离线状态下连不上。蓝牙?慢得像蜗牛在跑步。你急得团团转,突然灵机一动:用电脑直接传啊!可是怎么在浏览器里实现局域网P2P大文件传输,还得支持断点续传?别急,今天咱们就聊聊这个技术方案。 技术背景:P2P不是什么新鲜玩意儿 P2P(点对点)传输在局域网里其实挺常见的,BT下载就是经典案例。但咱们今天聊的是纯前端实现,意思是完


【云计算】利用 LVS 构建集群实现负载均衡 | 集群的概念 | 单服务器性能瓶颈验证例子 | LVS 基础 | LVS 构建负载均衡集群实操步骤
王平渊2026/1/15

利用 LVS 构建集群实现负载均衡 LVS 是构建高性能、高可靠负载均衡集群的利器,其内核态转发机制和丰富的调度算法,使其成为大规模集群场景的首选方案。在实际应用中,需根据业务场景选择合适的工作模式(DR 模式为最优选择),并结合 Keepalived 实现高可用,最终解决单服务器的性能瓶颈问题。 Ⅰ. 集群(Cluster)基础 0x00 集群的概念 集群(Cluster),是一组相互独立且相互依赖、通过高速网络互联的计算机组成的计算机组,以单一模式加以管理,为用户提供统一服务。 从用户视角


Excel/WPS 表格数据合并操作指南
GalenZhang8882026/1/6

Excel/WPS 表格数据合并操作指南 场景一:同一个文件,不同工作表(Sheet) 适用情况:数据都在同一个 Excel 文件里,比如在 Sheet1 和 Sheet2,都有共同的 A列 作为关联。 1. 推荐公式:XLOOKUP 公式示例: =XLOOKUP(A2, Sheet2!A:A, Sheet2!D:D) 2. 参数详细说明 A2(查找值): 当前表格(Sheet1)中你要拿去匹配的那个单元格(通常是 ID、姓名等)。Sheet2!A:A(查找数组): 去哪里找这个 ID?即 S


MySQL 版本演进全景图:从 5.6 到 8.4 的技术变革与行业实践
刘一说2025/12/29

文章目录 一、版本演进时间线概览二、核心功能迭代:从基础架构到现代数据库1. 数据类型与存储引擎革新2. 查询语言与计算能力3. 事务与一致性 三、架构与性能优化:从单机到云原生1. 复制与高可用2. 性能调优 四、安全与兼容性:从传统认证到现代密钥管理1. 认证机制演变2. 加密与审计 五、典型场景适配建议六、未来趋势与行业挑战结语 一、版本演进时间线概览 版本发布时间核心突破行业定位5.62013年在线 DDL、性能优化传统 OLTP 基础架构5.7201

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客