網絡:應用層
我們要知道,所有的問題解決都是在應用層。:happy:
協議是一種約定,也就是雙方約定好的結構化的數據。但是在讀寫數據時我們都是按字符串的方式來發送接受的,那么我們應該如和傳輸結構化的數據呢?應用層協議,TCP面向字節流導致的粘包問題就是在應用層協議中要解決的問題之一。
自定義協議
理解TCP和UDP為什么支持全雙工
在任何一臺主機上,TCP
連接既有發送緩沖區,又有接受緩沖區,所以在內核中可以在發消息的同時,也可以收消息,也就是全雙工。
但是UDP
沒有發送緩沖區(不使用SentQueue
)調用sendto
后UDP
直接將數據交給內核,內核直接發送。UDP
具有接收緩沖區,但是這個接收緩沖區不能保證收到的 UDP
報的順序和發送 UDP
報的順序一致,如果緩沖區滿了,再到達的 UDP
數據就會被丟棄
為什么會這樣設計,TCP、UDP協議詳解會給你答案
實現網絡計算器方案
我們要實現一個網絡版的計算器,由客戶端把要計算的兩個數和操作發給服務器,服務器經過計算后將結果返回給客戶端。
- 定義結構體來表示我們需要交互的信息
- 發送數據時將這個結構體按照一個規則轉換成字符串, 接收到數據的時候再按照相同的規則把字符串轉化回結構體
- 這個過程叫做 “序列化” 和 “反序列化”
基本方案是,定義一個protocol
類,一個req
和resp
類,req
和resp
里面就是結構化的數據,req
,resp
類中實現序列化和反序列化。protocol
類中實現Encode
和Decode
方法,添加報頭和去掉報頭。序列化和反序列化中我們有現成的方案 --Jsoncpp
網絡版本計算器
守護進程化
// 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
提供了直觀的API
,使得處理JSON
數據變得簡單 - 高性能:
Jsoncpp
的性能經過優化,能夠高效地處理大量JSON
數據 - 全面支持:支持
JSON
標準中的所有數據類型,包括對象、數組、字符串、數字、布爾值和null
- 錯誤處理:在解析
JSON
數據時,Jsoncpp
提供了詳細的錯誤信息和位置,方便開發者調試。
當使用 Jsoncpp
庫進行 JSON
的序列化和反序列化時,確實存在不同的做法和工具類可供選擇。以下是對 Jsoncpp
中序列化和反序列化操作的詳細介紹:
Jsoncpp
庫的簡單使用方法
Http協議
雖然我們說,應用層協議是我們程序猿自己定的,但實際上,已經有大佬們定義了一些現成的,又非常好用的應用層協議,供我們直接參考使用。HTTP
(超文本傳輸協議)就是其中之一。
在互聯網世界中,HTTP
(HyperText Transfer Protocol,超文本傳輸協議)是一個至關重要的協議。它定義了客戶端(如瀏覽器)與服務器之間如何通信,以交換或傳輸超文本(如 HTML
文檔)。
HTTP
協議是客戶端與服務器之間通信的基礎。客戶端通過 HTTP 協議向服務器發送請求,服務器收到請求后處理并返回響應。HTTP
協議是一個無連接、無狀態的協議,即每次請求都需要建立新的連接,且服務器不會保存客戶端的狀態信息。
認識URL
URL就是網址
如:http://wangruqin.site/
urlencode 和 urldecode
像 / ? : 等這樣的字符,已經被 url 當做特殊意義理解了,因此這些字符不能隨意出現
比如,某個參數中需要帶有這些特殊字符,就必須先對特殊字符進行轉義
轉義的規則如下:
將需要轉碼的字符轉為 16 進制,然后從右到左,取 4 位(不足 4 位直接處理),每 2 位做一位,前面加上%,編碼成%XY 格式
例如:
“+” 被轉義成了 “%2B”
urldecode
就是urlencode
的逆過程;urlencode工具
HTTP協議請求與響應格式
HTTP請求
- 首行: [方法] + [url] + [版本]
Header
: 請求的屬性, 冒號分割的鍵值對;每組屬性之間使用\r\n
分隔;遇到空行表示Header
部分結束Body
: 空行后面的內容都是Body
,Body
允許為空字符串,如果Body
存在,則在Header 中會有一個Content-Length
屬性來標識Body
的長度
HTTP響應
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>...
- 首行:[版本號] + [狀態碼] + [狀態碼解釋]
Header
:請求的屬性,冒號分割的鍵值對;每組屬性之間使用\r\n
分隔;遇到空行表示Header
部分結束Body
:空行后面的內容都是Body
,Body
允許為空字符串. 如果Body
存在,則在Header
中會有一個Content-Length
屬性來標識Body
的長度;如果服務器返回了一個html
頁面,那么html
頁面內容就是在body
中
HTTP的方法
最常見的就是GET
和POST
方法
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
特性:返回允許的方法,如 GET
、POST
等
HTTP的狀態碼
狀態碼 | 含義 | 應用樣例 |
---|---|---|
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
發起請求
HTTP/1.1 301 Moved Permanently\r\n
Location: https://www.new-url.com\r\nHTTP/1.1 302 Found\r\n
Location: https://www.new-url.com\r\n
HTTP 常見 Header
- Content-Type:數據類型(text/html)
- Content-Length:Body的長度
- Host:客戶端告訴服務器,請求的資源在哪個主機的哪個端口上
- User-Agent:聲明用戶的操作系統和瀏覽器版本信息
- Referer:當前頁面是從哪個頁面跳轉過來的
- Location:搭配3XX狀態碼使用,告訴客戶端接下來要去哪里訪問
- Cookie:用于在客戶端存儲少量信息,通常用戶實現會話(session)的功能
關于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.com 或 Host: 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/json 或 Content-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-cache 或 Cache-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-8 或 Content-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=86400 或 Cache-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.0 或 Server: Apache/2.4.54 | |
Connection | 控制連接是否保持(HTTP/1.1 默認keep-alive ,關閉為close ) | Connection: keep-alive 或 Connection: close |
補充說明:
- 部分
Header
字段(如Cache-Control
、Content-Type
)在請求頭和響應頭中均可使用,但作用對象不同(請求頭控制客戶端行為,響應頭控制服務器行為)。 - 標頭名稱不區分大小寫,但通常約定使用首字母大寫(如
User-Agent
而非user-agent
)。 - 擴展
Header
(如X-Forwarded-For
、X-Requested-With
)常用于特定場景(如代理、AJAX 請求標識),但非HTTP
標準定義。
嗯~沒錯這就是那個被面試官說是LJ
的項目👍💩
💩
基于Reactor反應堆+Epoll多路轉接的HTTP服務器
附錄:
HTTP歷史及版本核?技術與時代背景
HTTP(Hypertext Transfer Protocol,超?本傳輸協議)作為互聯網中瀏覽器和服務器間通信的基石,經歷了從簡單到復雜、從單?到多樣的發展過程。以下將按照時間順序,介紹HTTP的主要版本、核心技術及其對應的時代背景。
HTTP/0.9
核心技術:
- 僅支持
GET
請求?法。 - 僅支持純?本傳輸,主要是
HTML
格式。 - 無請求和響應頭信息。
時代背景:
- 1991年,HTTP/0.9版本作為HTTP協議的最初版本,用于傳輸基本的超文本
HTML
內容。 - 當時的互聯網還處于起步階段,網頁內容相對簡單,主要以文本為主。
HTTP/1.0
核心技術:
- 引入
POST
和HEAD
請求?法。 - 請求和響應頭信息,?持多種數據格式(MIME)。
- 支持緩存(cache)。
- 狀態碼(status code)、多字符集支持等。
時代背景:
- 1996年,隨著互聯?的快速發展,網頁內容逐漸豐富,HTTP/1.0版本應運而生。
- 為了滿足日益增長d的網絡應用需求,HTTP/1.0增加了更多的功能和靈活性。
- 然而,HTTP/1.0的?作方式是每次
TCP
連接只能發送?個請求,性能上存在?定局限。
HTTP/1.1
核心技術:
- 引?持久連接(persistent connection),支持管道化(pipelining)。
- 允許在單個
TCP
連接上進行多個請求和響應,提高了性能。 - 引?分塊傳輸編碼(chunked transfer encoding)。
- 支持
Host
頭,允許在?個IP地址上部署多個Web
站點。
時代背景:
-
1999年,隨著網頁加載的外部資源越來越多,HTTP/1.0的性能問題愈發突出。
-
HTTP/1.1通過引?持久連接和管道化等技術,有效提高了數據傳輸效率。
-
同時,互聯網應用開始呈現出多元化、復雜化的趨勢,HTTP/1.1的出現滿滿足了這些需求。
HTTP/2.0
核心技術:
- 多路復用(multiplexing),?個TCP連接允許多個HTTP請求。
- ?進制幀格式(binary framing),優化數據傳輸。
- 頭部壓縮(header compression),減少傳輸開銷。
- 服務器推送(server push),提前發送資源到客戶端。
時代背景:
-
2015年,隨著移動互聯?的興起和云計算技術的發展,網絡應用對性能的要求越來越高。
-
HTTP/2.0通過多路復用、?進制幀格式等技術,顯著提高了數據傳輸效率和網絡性能。
-
同時,HTTP/2.0還?持加密傳輸(HTTPS),提高了數據傳輸的安全性。
HTTP/3.0
核心技術:
-
使用
QUIC
協議替代TCP
協議,基于UDP
構建的多路復用傳輸協議。 -
減少了
TCP
三次握?及TLS
握手時間,提高了連接建立速度。 -
解決了
TCP
中的線頭阻塞問題,提高了數據傳輸效率。
時代背景:
-
2022年,隨著5G、物聯?等技術的快速發展,網絡應用對實時性、可靠性的要求越來越高。
-
HTTP/3.0通過使用
QUIC
協議,提高了連接建立速度和數據傳輸效率,滿足了這些需求。 -
同時,HTTP/3.0還支持加密傳輸(HTTPS),保證了數據傳輸的安全性。
用對性能的要求越來越高。 -
HTTP/2.0通過多路復用、?進制幀格式等技術,顯著提高了數據傳輸效率和網絡性能。
-
同時,HTTP/2.0還?持加密傳輸(HTTPS),提高了數據傳輸的安全性。