网络编程之UDP广播与粘包问题

一,广播简介

从上述讲的例⼦中,不管是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用于对套接字进行配置,常用于开启广播功能。

cpp 复制代码
#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)

cpp 复制代码
#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)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>

#define BUF_SIZE 1024

int 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 由于以报文为单位,不会产生粘包问题。

相关推荐
sunfove9 小时前
光网络的立交桥:光开关 (Optical Switch) 原理与主流技术解析
网络
Kevin Wang72712 小时前
欧拉系统服务部署注意事项
网络·windows
min18112345612 小时前
深度伪造内容的检测与溯源技术
大数据·网络·人工智能
汤愈韬12 小时前
NAT策略
网络协议·网络安全·security·huawei
汤愈韬12 小时前
Full Cone Nat
网络·网络协议·网络安全·security·huawei
zbtlink13 小时前
现在还需要带电池的路由器吗?是用来干嘛的?
网络·智能路由器
桌面运维家13 小时前
vDisk配置漂移怎么办?VOI/IDV架构故障快速修复
网络·架构
dalerkd13 小时前
忙里偷闲叙-谈谈最近两年
网络·安全·web安全
汤愈韬14 小时前
NAT ALG (应用层网关)
网络·网络协议·网络安全·security·huawei
运维栈记15 小时前
虚拟化网络的根基-网络命名空间
网络·docker·容器