UDP(User Datagram Protocol,RFC 768)位於傳輸層,提供**無連線、不可靠、無序**的資料報傳遞服務。適用於「快、少、可容忍丟包」場景:DNS、NTP、VoIP、遊戲狀態同步、廣播發現等。
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source Port | Destination Port |
+--------+--------+--------+--------+
| Length | Checksum |
+--------+--------+--------+--------+
為防止錯誤遞送,校驗和包含 IP 層資訊:
struct PseudoHeader {
uint32_t src_ip;
uint32_t dst_ip;
uint8_t zero;
uint8_t protocol; // 17
uint16_t udp_len;
};
// 計算:將偽頭部 + UDP頭部 + 數據 視為 16bit 字序列求和,溢位回卷,最後取反。
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(LOCAL_PORT);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sock, (sockaddr*)&addr, sizeof(addr));
// 發送
sendto(sock, buf, len, 0, (sockaddr*)&dst, sizeof(dst));
// 接收(阻塞)
sockaddr_in from; socklen_t flen = sizeof(from);
int n = recvfrom(sock, buf, MAX, 0, (sockaddr*)&from, &flen);
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)),目標 IP 設為 255.255.255.255 或子網廣播位址。IP_ADD_MEMBERSHIP 加入組播群組,IP_MULTICAST_TTL 設定跳數。fcntl(sock, F_SETFL, O_NONBLOCK) 或 WSAAsyncSelect/IOCP。IP_PKTINFO (Linux) / IP_RECVDSTADDR (BSD) 獲取目的 IP/介面,實現多介面 Server 回覆正確源 IP。| 誤區 | 正確做法 |
|---|---|
| 假設 UDP 不會丟包/亂序 | 應用層實現 ACK/重傳/序號/去重(如 QUIC、RUDP、ENet) |
| 單次 sendto 必對應單次 recvfrom | 網路可能合併/分片,應用層自行定義幂邊界(長度前綴/分隔符) |
| 忽略 MTU 導致 IP 分片 | 載荷控制在 1400 字節內(乙太網 MTU 1500 - IP 20 - UDP 8) |
| 不驗證來源 IP/埠 | recvfrom 返回的 sockaddr_in 必須校驗,防偽造/放大攻擊 |