TCP 與 UDP 協議的 socket 通信
剛剛有同事問我,tcp 是怎麼進行 socket 通訊的,udp 能進行 socket 通信嘛,想想這些基礎的知識竟一下子語塞,不知道怎麼回答了,在此,我整理了一下相關知識點,以公衆號文章的形式發表一下,個人粗淺的理解,如有不當之處,請各位大佬多多指點修正。
現在進入正文,咱們先了解一下 socket, 說到 socket, 就得說到互聯網的一個架構,c/s 架構,c/s 是客戶端和服務端 英文的首字母,咱們舉一個最常見應用到這個架構的例子,大部分的小夥伴都會玩王者榮耀吧,玩王者就必須要連接一個服務器一般是騰訊雲服務器,對於我們玩家來說管理王者的騰訊雲服務器就是服務端,服務端有了,那誰是客戶端呢,所謂客戶就是我們這些玩王者的小夥伴,客戶端當然就是王者榮耀 app 了。
簡單說完了 c/s, 我們再來用一張圖直觀演示一下 socket 在互聯網中的位置
_ 在網絡通信中,Socket 端點由 IP 地址和端口號標識;而在編程中,Socket 是封裝了通信能力的操作系統接口。
_ 簡單的_
說了一下 socket, 咱們再說一下 TCP 協議,tcp 協議屬於網絡協議,什麼叫網絡協議呢,通俗點說 就是兩臺互聯網機器 雙方就通信如何進行所必須共同遵守的約定和通信規則的集合。在網絡上通信的雙方只有遵守相同的協議,才能正確地交流信息,就像人們交談時要使用同一種語言一樣,如果談話裏使用不同的語言,就會造成雙方都不知所云,交流就被迫中斷_
_ 說到 tcp 協議大家應該很容易想到的就是三次握手,四次揮手,話不多說,咱先上圖,便於大家理解:_
爲什麼創建鏈接需要 3 步,而斷開鏈接則需要 4 步呢?
可以看到,三次握手之前是沒有數據傳輸的,並且其中第二次是一次性發送了一個請求和一個確認。所以減少了一次操作。而四次揮手涉及到數據的傳輸,所以不可能簡化成三次揮手。(四次揮手也是不同於三次握手,四次揮手也是建立在雙向鏈接通道的基礎之上的,而三次握手的時候該雙向通道還未建立成功),如下圖
FIN_WAIT_1:代表主動發起斷開鏈接請求
FIN_WAIT_2:代表此時的 Client 端不會再主動向 Server 端發送數據
TIME_WAIT:代表 Client 端還要回復最後一條確認消息,回覆完畢後雙向鏈接正式關閉
CLOSE_WAIT:代表關閉等待
LAST_ACK:代表持續的確認(即只要 Client 端沒有回覆第 4 條信息,Server 端就不斷嘗試發送斷開鏈接的 FIN 請求)
別講太複雜了,咱的理解目前也只是到這個層面,下面再來看看 udp 協議,UDP 協議是一種基於數據報的格式(也被稱爲基於消息),不同於 TCP 的字節流格式。UDP 的數據報格式是有頭有尾的,這一點很重要。對應下圖
另外,udp 協議是不需要建立雙向鏈接通道的,並且 udp 發消息發一次就不會管了,不管收沒收到。
最後用一張表格比較一下這兩大協議,讓大家看得更直觀一些
講完這兩大協議和 socket 的概念,最後咱講講,他們是怎麼通過 socket 通信的吧。
TCP Socket:面向連接,可靠傳輸(類似打電話)
UDP Socket :無連接,不可靠傳輸(類似發短信)
這邊咱直接上代碼,看不懂的可以跳過:
服務端代碼(C 語言示例)
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
int main() {
// 1. 創建 TCP Socket
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
// 2. 綁定 IP 和端口
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY; // 監聽所有網卡
addr.sin_port = htons(8080); // 端口號
bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
// 3. 開始監聽
listen(server_fd, 5); // 允許最多 5 個客戶端排隊
// 4. 接受客戶端連接
int client_fd = accept(server_fd, NULL, NULL);
// 5. 發送數據
char msg[] = "Hello TCP Client!";
send(client_fd, msg, sizeof(msg), 0);
// 6. 關閉連接
close(client_fd);
close(server_fd);
return 0;
}
客戶端代碼
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
// 1. 創建 TCP Socket
int sock = socket(AF_INET, SOCK_STREAM, 0);
// 2. 連接服務器
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); // 服務器 IP
connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
// 3. 接收數據
char buffer[1024] = {0};
recv(sock, buffer, 1024, 0);
printf("Server says: %s\n", buffer);
// 4. 關閉連接
close(sock);
return 0;
}
TCP Socket 特點
優點:
-
可靠傳輸(自動重傳丟失的數據包)
-
保證數據順序(先發的數據先到)
-
流量控制(防止發送過快導致接收方緩衝區溢出)
缺點:
-
三次握手建立連接,延遲較高
-
頭部開銷大(20~60 字節)
-
不適合實時性要求高的場景(如視頻通話)
UDP socket 通訊流程
服務端代碼(c 語言):
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main() {
// 1. 創建 UDP Socket
int sock = socket(AF_INET, SOCK_DGRAM, 0);
// 2. 綁定 IP 和端口
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(8080);
bind(sock, (struct sockaddr*)&addr, sizeof(addr));
// 3. 接收數據(無連接,直接收)
char buffer[1024];
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
recvfrom(sock, buffer, 1024, 0, (struct sockaddr*)&client_addr, &addr_len);
// 4. 發送數據(無連接,直接發)
char msg[] = "Hello UDP Client!";
sendto(sock, msg, sizeof(msg), 0, (struct sockaddr*)&client_addr, addr_len);
// 5. 關閉 Socket
close(sock);
return 0;
}
客戶端代碼
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
// 1. 創建 UDP Socket
int sock = socket(AF_INET, SOCK_DGRAM, 0);
// 2. 發送數據(無需 connect)
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
char msg[] = "Hello Server!";
sendto(sock, msg, sizeof(msg), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));
// 3. 接收數據
char buffer[1024] = {0};
recvfrom(sock, buffer, 1024, 0, NULL, NULL);
printf("Server says: %s\n", buffer);
// 4. 關閉 Socket
close(sock);
return 0;
}
UDP Socket 特點
優點:
-
無連接,延遲低(適合實時應用)
-
頭部開銷小(僅 8 字節)
-
適合廣播 / 多播(如視頻直播)
缺點:
-
不保證數據可靠到達(可能丟包)
-
不保證數據順序(後發的包可能先到)
-
無流量控制(發送過快可能導致丟包)
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/58EixVHdm2TspZno7hKf9A