一,廣播簡介
從上述講的例?中,不管是TCP協議還是UDP協議,都是”單播”, 就是”點對點”的進?通信,如果要對網絡里面的所有主機進?通信,實現”點對多”的通信,我們可以使用UDP中的?播通信。
理論上可以像播放電視節目?樣在整個Internet 上發送廣播數據,但是幾乎沒有路由器轉發廣播數據,所以,廣播程序只能應用在本地子網中。
廣播的特點:
1.?播需要有發送?和接收?,必須有?些線程在機器上監聽到來的數據。?播的缺點是如果有多個進程都發送?播數據,?絡就會阻塞,?絡性能便會受到影響。
2.?播發送不是循環給?絡中的每?個IP發送數據,而是給?絡中?個特定的IP發送信息,這個IP就是?播地址,?播發送方:使?setsockopt打開SO_BROADCAST, 設置廣播地址 255.255.255.255,設置?播端口號。廣播接收方:將套接字綁定到指定的廣播端口號, 監聽數據到來。
3.?播數據發送只能采?UDP協議,?播UDP與單播UDP的區別就是IP地址不同,?播使?廣播地址255.255.255.255,將消息發送到在同?廣播網絡上的每個主機。
廣播的實現:
發送方:
1.調用 setsockopt()?打開 SO_BROADCAST。
2.使用廣播地址 255.255.255.255。
3.設置廣播端口號,向局域網廣播消息。
接收方:
1.將套接字綁定到廣播端口。
2.監聽數據到來,處理接收的廣播消息。
注意:廣播通信只能使用 UDP 協議,區別在于目標 IP 使用廣播地址 255.255.255.255。
二,setsockopt()函數詳解
setsockopt和getsockopt用于對套接字進行配置,常用于開啟廣播功能。
#include <sys/types.h>
#include <sys/socket.h>int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
sock:套接字描述符。
level:選項所在協議層(如 SOL_SOCKET、IPPROTO_IP、IPPROTO_TCP)。
optname:選項名稱(常見如 SO_BROADCAST)。
optval:選項值。
optlen:選項長度。
常見選項:
INADDR_ANY (0.0.0.0):表示綁定本機所有網卡地址。
INADDR_BROADCAST (255.255.255.255):廣播地址,消息只在當前局域網有效。
三,粘包問題
1.什么是粘包?
在 TCP 通信中,發送方發送的多個小數據包可能會被合并到一起,接收方從緩沖區讀取時無法分辨消息邊界,這就是 粘包。
注意:UDP 不會發生粘包問題,因為它以報文為單位,每次 recv 只能讀取一個完整 UDP 包。
2.粘包產生原因
1.發送方為了提高效率,等待緩沖區滿再發送。
2.TCP 協議中的 Nagle 算法?會將多個小包合并成大包。
3.接收方處理不及時,導致多個包堆積在緩沖區中一起被讀出。
3.解決辦法
自定義報文格式:
使用 包頭 + 數據長度 + 數據內容?的格式來傳輸。
包頭:標識包的起始位置。
長度:告訴接收方應該讀取多少字節。
包尾:標識包的結束。
示例:
[包頭][數據長度][數據內容][包尾]
接收時:
先讀取包頭,判斷一個數據包的開始。根據數據長度讀取完整數據。處理完后繼續讀取下一個包。
4.UDP廣播示例代碼
發送端(send.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>int main() {int sock;struct sockaddr_in broadcastAddr;char *msg = "Hello, this is a UDP broadcast!";int broadcastPermission = 1;// 創建 UDP 套接字sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0) {perror("socket failed");exit(1);}// 設置套接字支持廣播setsockopt(sock, SOL_SOCKET, SO_BROADCAST,&broadcastPermission, sizeof(broadcastPermission));// 設置廣播地址memset(&broadcastAddr, 0, sizeof(broadcastAddr));broadcastAddr.sin_family = AF_INET;broadcastAddr.sin_port = htons(8888);broadcastAddr.sin_addr.s_addr = inet_addr("255.255.255.255");// 發送廣播消息while (1) {sendto(sock, msg, strlen(msg), 0,(struct sockaddr *)&broadcastAddr, sizeof(broadcastAddr));printf("Broadcast message sent: %s\n", msg);sleep(2);}close(sock);return 0;
}
接收端(receive.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>#define BUF_SIZE 1024int main() {int sock;struct sockaddr_in recvAddr;char buffer[BUF_SIZE];socklen_t addr_len = sizeof(recvAddr);// 創建 UDP 套接字sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0) {perror("socket failed");exit(1);}// 綁定端口memset(&recvAddr, 0, sizeof(recvAddr));recvAddr.sin_family = AF_INET;recvAddr.sin_port = htons(8888);recvAddr.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(sock, (struct sockaddr *)&recvAddr, sizeof(recvAddr)) < 0) {perror("bind failed");exit(1);}// 循環接收廣播while (1) {int recvLen = recvfrom(sock, buffer, BUF_SIZE, 0,(struct sockaddr *)&recvAddr, &addr_len);buffer[recvLen] = '\0';printf("Received broadcast: %s\n", buffer);}close(sock);return 0;
}
運行結果:
五,總結
1.DP 廣播適合局域網內的點對多通信,簡單高效。
2.使用 setsockopt()?配置 SO_BROADCAST,通過廣播地址 255.255.255.255?實現廣播。
3.TCP 粘包問題在通信中較常見,可以通過自定義報文格式來解決。
4.UDP 由于以報文為單位,不會產生粘包問題。