博客封面

✨✨所属专栏:Linux✨✨

✨✨作者主页:嶔某✨✨

网络:应用层

我们要知道,所有的问题解决都是在应用层。:happy:

协议是一种约定,也就是双方约定好的结构化的数据。但是在读写数据时我们都是按字符串的方式来发送接受的,那么我们应该如和传输结构化的数据呢?应用层协议,TCP面向字节流导致的粘包问题就是在应用层协议中要解决的问题之一。

自定义协议

理解TCP和UDP为什么支持全双工

在任何一台主机上,TCP连接既有发送缓冲区,又有接受缓冲区,所以在内核中可以在发消息的同时,也可以收消息,也就是全双工。

但是UDP没有发送缓冲区(不使用SentQueue)调用sendtoUDP直接将数据交给内核,内核直接发送。UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的 UDP 报的顺序和发送 UDP 报的顺序一致,如果缓冲区满了,再到达的 UDP 数据就会被丢弃

为什么会这样设计,TCP、UDP协议详解会给你答案

image-20250610150454883

实现网络计算器方案

我们要实现一个网络版的计算器,由客户端把要计算的两个数和操作发给服务器,服务器经过计算后将结果返回给客户端。

image-20250610145848451

基本方案是,定义一个protocol类,一个reqresp类,reqresp里面就是结构化的数据,reqresp类中实现序列化和反序列化。protocol类中实现EncodeDecode方法,添加报头和去掉报头。序列化和反序列化中我们有现成的方案 --Jsoncpp

网络版本计算器

守护进程化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// daemon.hpp
#pragma once
#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include "log.hpp"

const std::string null_dev = "/dev/null";
using namespace LogModule;
// 守护进程
void daemon()
{
// 1. 忽略IO,子进程退出信号
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
// 2. 新起一个进程,并退出父进程
if (fork() > 0)
exit(1);
// 3. 新建一个会话
setsid();
// 4. 更改进程的当前执行路径
chdir("/");
// 5. 关闭标准输入输出错误 可能导致本来输出到显示器的东西出错
// 建议重定向到 /dev/null 文件里(无底洞)
int fd = ::open(null_dev.c_str(), O_RDWR);
if (fd < 0)
LOG(LogLevel::FATAL) << "open dev/null error";
else
{
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
}
}

Jsoncpp

Jsoncpp 是一个用于处理 JSON 数据的 C++ 库。它提供了将 JSON 数据序列化为字符串以及从字符串反序列化为 C++ 数据结构的功能。Jsoncpp 是开源的,广泛用于各种需要处理 JSON 数据的 C++ 项目中

当使用 Jsoncpp 库进行 JSON 的序列化和反序列化时,确实存在不同的做法和工具类可供选择。以下是对 Jsoncpp 中序列化和反序列化操作的详细介绍:

Jsoncpp库的简单使用方法

Http协议

虽然我们说,应用层协议是我们程序猿自己定的,但实际上,已经有大佬们定义了一些现成的,又非常好用的应用层协议,供我们直接参考使用。HTTP(超文本传输协议)就是其中之一。

在互联网世界中,HTTPHyperText Transfer Protocol,超文本传输协议)是一个至关重要的协议。它定义了客户端(如浏览器)与服务器之间如何通信,以交换或传输超文本(如 HTML 文档)。

HTTP 协议是客户端与服务器之间通信的基础。客户端通过 HTTP 协议向服务器发送请求,服务器收到请求后处理并返回响应。HTTP 协议是一个无连接、无状态的协议,即每次请求都需要建立新的连接,且服务器不会保存客户端的状态信息。

认识URL

URL就是网址

如:http://wangruqin.site/

urlencode urldecode

像 / ? : 等这样的字符,已经被 url 当做特殊意义理解了,因此这些字符不能随意出现

比如,某个参数中需要带有这些特殊字符,就必须先对特殊字符进行转义

转义的规则如下:

将需要转码的字符转为 16 进制,然后从右到左,取 4 位(不足 4 位直接处理),每 2 位做一位,前面加上%,编码成%XY 格式

例如:

image-20250610215446989

“+” 被转义成了 “%2B”

urldecode 就是 urlencode 的逆过程;

urlencode工具

HTTP协议请求与响应格式

HTTP请求

http请求

image-20250610220545622

HTTP响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HTTP / 1.1 200 OK
Server=nginx/1.24.0 (Ubuntu)
Date=Tue, 10 Jun 2025 14:13:01 GMT
Content-Type=text/html; charset=utf-8
Transfer-Encoding=chunked
Connection=keep-alive
Content-Encoding=

<!DOCTYPE html>
<html>
<head>
<!-- 页面元信息 -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Qin Home</title>
...

image-20250610222222249

HTTP的方法

image-20250610222339078

最常见的就是GETPOST方法

GET 方法

用途:用于请求 URL 指定资源

示例:GET /index.html HTTP/1.1

特性:指定资源经服务器端解析后返回响应内容

POST 方法

用途:用于传输实体的主体,通常用于提交表单数据

示例:POST /submit.cgi HTTP/1.1

特性:可以发送大量的数据给服务器,并且数据包含在请求体中

PUT 方法

用途:用于传输文件,将请求报文主体中的文件保存到请求 URL 指定的位置

示例:PUT /example.html HTTP/1.1

特性:不太常用,但在某些情况下,如RESTful API 中,用于更新资源

HEAD 方法

用途:与 GET 方法类似,但不返回报文主体部分,仅返回响应头

示例:HEAD /index.html HTTP/1.1

特性:用于确认 URL 的有效性及资源更新的日期时间等

DELETE 方法(不常用)

用途:用于删除文件,是 PUT 的相反方法

示例:DELETE /example.html HTTP/1.1

特性:按请求 URL 删除指定的资源

PTIONS 方法

用途:用于查询针对请求 URL 指定的资源支持的方法

示例:OPTIONS * HTTP/1.1

特性:返回允许的方法,如 GETPOST

HTTP的状态码

image-20250619230914943

状态码 含义 应用样例
100 Continue 上传大文件时,服务器告诉客户端可以继续上传
200 OK 问网站首页,服务器返回网页内容
201 Create 发布新文章,服务器返回文章创建成功
204 No Content 删除文章后,服务器返回“无内容”表示操作成功
301 Moved Permanently (永久重定向)网站换域名后,自动跳转到新域名;搜索引擎更新网站链接时使用
302 Found 或 See Other (临时重定向)用户登录成功后,重定向到用户首页
304 Not Modified 浏览器缓存机制,对未修改的资源返回 304 状态码
307 Temporary Redirect (临时重定向)临时重定向资源到新的位置(较少使用)
308 Permanent Redirect (永久重定向)永久重定向资源到新的位置(较少使用)
400 Bad Request 填写表单时,格式不正确导致提交失败
401 Unauthorized 访问需要登录的页面时,未登录或认证
403 Forbidden 尝试访问你没有权限查看的页面
404 Not Found 访问不存在的网页链接
500 Internal Server Error 服务器崩溃或数据库错误导致页面无法加载
502 Bad Gateway 使用代理服务器时,代理服务器无法从上游服务器获取有效响应
503 Service Unavailable 服务器维护或过载,暂时无法处理请求

HTTP中无论是 301 还是 302 重定向 服务器收到请求后除了返回 301 302 状态码,还会再头部中添加Location信息,用于告诉浏览器应该将请求重定向到哪个新的URL地址,浏览器收到回复后重新向 Location 发起请求

1
2
3
4
5
HTTP/1.1 301 Moved Permanently\r\n
Location: https://www.new-url.com\r\n

HTTP/1.1 302 Found\r\n
Location: https://www.new-url.com\r\n

HTTP 常见 Header

关于Header中的connection

这个字段主要是为了控制服务器和客户端之间的连接状态,也就是支持客户端与服务器之间持久连接(响应完成后不立刻关闭TCP连接)这样可以在一个连接上发送多个请求和接受多个响应

在HTTP/1.1中默认就是使用持久连接,HTTP/1.0中默认的连接是非持久的,如果在HTTP/1.0中希望是持久连接,则需要在Header中显示添加该字段:Connection: keep-alive,如果在HTTP/1.1中希望不是持久连接添加该字段:Connection: close

常见Header表

以下是 HTTP 协议中常见的 Header 字段表格,按请求头(Request Headers)和响应头(Response Headers)分类

类别 字段名称 作用描述 常见示例
请求头 Host 指定请求的服务器域名和端口号,HTTP/1.1 必需字段 Host: www.example.comHost: api.example.com:8080
User-Agent 标识发送请求的客户端(浏览器、爬虫等)信息 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/114.0.0.0
Accept 客户端可接受的响应数据格式(MIME 类型) Accept: text/html, application/json
Accept-Encoding 客户端支持的内容编码方式(如压缩格式) Accept-Encoding: gzip, deflate, br
Accept-Language 客户端可接受的自然语言(如中文、英文) Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Authorization 用于身份验证,通常携带令牌(如 Bearer Token)或基本认证信息 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Content-Type 请求体的数据格式(仅在 POST/PUT 等有请求体时使用) Content-Type: application/jsonContent-Type: multipart/form-data
Content-Length 请求体的字节长度(帮助服务器确定数据是否完整) Content-Length: 1024
Cookie 客户端存储的 Cookie 信息,由服务器通过Set-Cookie设置 Cookie: sessionId=abc123; username=user1
Referer 标识当前请求的来源页面(防盗链、统计来源常用) Referer: https://www.example.com/login
Origin 跨域请求时,标识请求的源站(协议 + 域名 + 端口),不含路径 Origin: https://www.example.com
Cache-Control 客户端对缓存的控制策略(如禁止缓存、强制验证等) Cache-Control: no-cacheCache-Control: max-age=3600
If-Modified-Since 条件请求:仅当资源在指定时间后修改过才返回,否则返回 304 If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT
Range 断点续传:请求资源的部分内容(如从第 100 字节开始) Range: bytes=100-Range: bytes=0-499, 500-999
响应头 Status 响应状态码及描述(如 200 OK、404 Not Found) Status: 200 OK
Content-Type 响应体的数据格式(MIME 类型),帮助客户端解析数据 Content-Type: text/html; charset=utf-8Content-Type: image/jpeg
Content-Length 响应体的字节长度 Content-Length: 2048
Content-Encoding 响应体的编码方式(如 gzip 压缩),客户端需先解压 Content-Encoding: gzip
Set-Cookie 服务器向客户端设置 Cookie,可包含过期时间、域名、路径等属性 Set-Cookie: sessionId=abc123; Expires=Wed, 21 Oct 2024 07:28:00 GMT
Cache-Control 服务器对缓存的控制策略(如客户端可缓存时长、是否可共享等) Cache-Control: public, max-age=86400Cache-Control: no-store
Expires 资源的过期时间(HTTP/1.0 遗留字段,与Cache-Control配合使用) Expires: Thu, 22 Oct 2023 07:28:00 GMT
Last-Modified 资源最后修改的时间,用于客户端缓存验证(配合If-Modified-Since Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT
ETag 资源的唯一标识(如哈希值),用于更精确的缓存验证(配合If-None-Match ETag: "abc123"ETag: W/"abc123"(弱验证器)
Location 重定向时,指定新的资源 URL(配合 3xx 状态码使用) Location: https://www.example.com/new-page
Access-Control-Allow-Origin 跨域资源共享(CORS):允许访问的源站(* 表示允许所有) Access-Control-Allow-Origin: https://www.example.com*
Access-Control-Allow-Methods CORS:允许的请求方法(如 GET、POST、PUT) Access-Control-Allow-Methods: GET, POST, OPTIONS
Server 服务器的软件信息(如 Web 服务器类型、版本) Server: Nginx/1.21.0Server: Apache/2.4.54
Connection 控制连接是否保持(HTTP/1.1 默认keep-alive,关闭为close Connection: keep-aliveConnection: close

补充说明:

嗯~没错这就是那个被面试官说是LJ的项目:+1::hankey: :poop:

基于Reactor反应堆+Epoll多路转接的HTTP服务器

附录:

HTTP历史及版本核⼼技术与时代背景

HTTP(Hypertext Transfer Protocol,超⽂本传输协议)作为互联网中浏览器和服务器间通信的基石,经历了从简单到复杂、从单⼀到多样的发展过程。以下将按照时间顺序,介绍HTTP的主要版本、核心技术及其对应的时代背景。

HTTP/0.9

核心技术:

时代背景:

HTTP/1.0

核心技术:

时代背景:

HTTP/1.1

核心技术:

时代背景:

HTTP/2.0

核心技术:

时代背景:

HTTP/3.0

核心技术:

时代背景: