????????TCP(Transmission Control Protocol)與UDP(User Datagram Protocol)是 網絡通訊 中最基礎也最常用的兩種 傳輸層 協議。
文章目錄
- 1. 簡介
- 2. OSI 與 TCP/IP 模型中的定位
- 3. 協議原理與關鍵機制
- 3.1 UDP
- 3.2 TCP
- 5. 實踐:Socket 接口示例
- C語言
- Go語言
- Python語言
- 6. 調優
1. 簡介
????????TCP 是1974年由早期的NCP(Network Control Protocol)逐漸演化出來的概念。它在1980年被拆分成了現在常見的TCP與IP協議,形成經典的 TCP/IP 協議簇。后來,UDP 在 RFC 768(互聯網工程任務協會,Internet Engineering Task Force, IETF,發布的一個標準文件)中發布,用于減少延遲、適應簡單的請求或應答環境,如DNS(域名系統)。
????????90年代后,TCP 持續優化擁塞控制算法(如Tahoe、Reno、CUBIC),在萬兆與云計算場景中處于核心地位。而UDP則在實時音視頻、VoIP(基于IP的語音傳輸,一種語音通話技術)、在線游戲等領域被廣泛使用。
2. OSI 與 TCP/IP 模型中的定位
TCP/IP模型將傳統的OSI理論模型簡化為4層結構,傳輸層分為TCP/UDP兩種機制。
3. 協議原理與關鍵機制
3.1 UDP
【注】
- 源/目的端口: 標識進程級別的通信端點
- 長度: 頭部與數據總長度,最小8字節
- 校驗和: 包含偽首部,檢驗UDP頭與數據的完整性
【機制】
- 無握手: 發送即完成,無三次握手
- 無重傳: 丟包不重發、無擁塞控制,由上層應用決定策略。
- 場景: 實時音視頻、DNS查詢等。實時性要求高,應用自有可靠機制或可忽略丟包。
3.2 TCP
【注】
- 序列號 / 確認號: 實現可靠傳輸的核心,按字節計數流
- Flags: URG,ACK,PSH,RST,SYN,FIN等,控制連接的建立,終止與數據推送。
- 窗口大小: 流量控制的關鍵,接收方通告自己緩存區的剩余空間
- 選項: 常見有最大報文段MSS、時間戳、窗口縮放等,用于性能優化。
【機制】
-
三次握手(3-way Handshake):
? ?1. 客戶端發送SYN,選擇輸出序列號x
? ?2. 服務端回應 SYN+ACK,確認號 x+1,并發送自己序列號 y
? ?3. 客戶端再發 ACK 確認號 y+1,一切就緒 -
四次揮手(4-way Teardown):
? ?1. 發起方發送 FIN。
? ?2. 對方 ACK。
? ?3. 對方再發 FIN。
? ?4. 原方 ACK,等待 TIME-WAIT 結束后真正釋放。 -
重傳
超時重傳(RTO): 基于往返時間(RTT)估算,動態調整超時重傳定時器。
快速重傳: 連續收到 3 個相同的ACK時,立即重傳疑似丟失的報文段,而無需等待超時。 -
擁塞控制算法
? ?1. 慢啟動: 指數增長擁塞窗口(cwnd),直到達到閾值
? ?2. 擁塞避免: 加法增大,線性增長cwnd
? ?3. 快速重傳與快速恢復: 檢測到丟包后,一方面減小閾值,一方面快速恢復到閾值區。
? ?4. CUBIC(linux默認),BBR(Google提出)等
5. 實踐:Socket 接口示例
下面以編程語言示例基礎的TCP和UDP的服務端與客戶端。
C語言
// UDP 客戶端示例:初始化并發送
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in serv;
memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(9000);
serv.sin_addr.s_addr = inet_addr("127.0.0.1");
char *msg = "Hello UDP";
sendto(sock, msg, strlen(msg), 0, (struct sockaddr*)&serv, sizeof(serv));// TCP 服務器示例:接受連接并回復
int sock = socket(AF_INET, SOCK_STREAM, 0);
bind(sock, (struct sockaddr*)&serv, sizeof(serv));
listen(sock, 5);
int conn = accept(sock, NULL, NULL);
char buf[1024];
int len = recv(conn, buf, sizeof(buf), 0);
send(conn, "Hello TCP", 9, 0);
close(conn);
Go語言
// UDP Echo 服務器
addr, _ := net.ResolveUDPAddr("udp", ":9000")
conn, _ := net.ListenUDP("udp", addr)
buf := make([]byte, 1024)
for {n, remote, _ := conn.ReadFromUDP(buf)conn.WriteToUDP(buf[:n], remote)
}// TCP 客戶端
conn, _ := net.Dial("tcp", "localhost:8000")
fmt.Fprintln(conn, "Hello TCP")
response, _ := bufio.NewReader(conn).ReadString('\n')
fmt.Println("Server replied:", response)
Python語言
# UDP 客戶端
import socket
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp.sendto(b"Ping", ("localhost", 9000))
msg, _ = udp.recvfrom(1024)
print(msg)# TCP 服務器
import socket
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.bind(("0.0.0.0", 8000))
srv.listen(1)
conn, addr = srv.accept()
data = conn.recv(1024)
conn.sendall(b"Hello TCP")
conn.close()
6. 調優
- TIME_WAIT消耗: 大量短連接會產生大量的TIME_WAIT,建議啟動連接復用、長連接或HTTP/2多路復用。
- MTU與分片: 超大UDP報文易被分片丟棄,建議應用層自行分片與重組。
- Nagle算法: TCP默認啟用Nagle,合并小包,可能會增加延遲,需要根據場景選擇是否禁用。
- 內核緩沖區調整: 高帶寬-時延環境下,增大send/recv緩沖區以避免吞吐瓶頸。
- 擁塞算法: Linux默認CUBIC,若要更低時延可使用BBR。