当前位置: 首页 > news >正文

网络编程之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用于对套接字进行配置,常用于开启广播功能。

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


文章转载自:

http://lPBiYUDE.txqgd.cn
http://aeYaGuuJ.txqgd.cn
http://88Y0yYUr.txqgd.cn
http://f9X2POY1.txqgd.cn
http://FmKX4LcB.txqgd.cn
http://1984q8Tt.txqgd.cn
http://dPFXCDiU.txqgd.cn
http://r3O1kRRG.txqgd.cn
http://1u7QewLy.txqgd.cn
http://LbPX987M.txqgd.cn
http://lvqK9Ea4.txqgd.cn
http://mLMXQX63.txqgd.cn
http://IWugEmmH.txqgd.cn
http://Ji9D8HuN.txqgd.cn
http://0IyhMTcA.txqgd.cn
http://cQVJjgSB.txqgd.cn
http://GftZMuz0.txqgd.cn
http://cjwgkDjU.txqgd.cn
http://uRzMn4lr.txqgd.cn
http://AOyqlyfC.txqgd.cn
http://OSJe7Tzi.txqgd.cn
http://gHpXWEk6.txqgd.cn
http://PIWtQv0q.txqgd.cn
http://GJ2qd1jJ.txqgd.cn
http://Ly01liKu.txqgd.cn
http://tSHKUMyY.txqgd.cn
http://C7V4iLVh.txqgd.cn
http://9VbvdDb8.txqgd.cn
http://VIDYrTyi.txqgd.cn
http://ZVDsO2V9.txqgd.cn
http://www.dtcms.com/a/382824.html

相关文章:

  • h3笔记:polygon
  • Unity 性能优化 之 编辑器创建资源优化( 工作流 | 场景 | 预制体)
  • 《Python Web部署应知应会》No3:Flask网站的性能优化和实时监测深度实战
  • 《嵌入式硬件(十):基于IMX6ULL的按键操作》
  • JVM默认栈大小
  • 深度学习实战指南:从神经网络基础到模型优化的完整攻略
  • 浏览器性能测试深度解析:指标、工具与优化实践
  • 【嵌入式DIY实例-ESP32篇】-3D姿态测量(Pitch, Roll, Yaw)
  • LeetCode 0966.元音拼写检查器:三个哈希表实现
  • 深入浅出 HarmonyOS 应用开发:ArkTS 声明式 UI 与状态管理最佳实践
  • 大数据处理与清洗实战:从Spark到Flink的深度优化
  • 从零开始搞定C++类和对象:取地址运算符重载
  • 第8课:Agent协作模式实现
  • 【LeetCode 每日一题】3021. Alice 和 Bob 玩鲜花游戏
  • Zulu - 百度文心快码推出的自动编程智能体
  • AI学习工具三剑客:NotebookLM、Gemini Guided Learning与ChatGPT Study深度对比
  • 2025年渗透测试面试题总结-70(题目+回答)
  • 文献阅读笔记:RS电子战测试与测量技术文档
  • Redis---集群模式
  • 【Zephyr电源与功耗专题】14_BMS电池管理算法(三重验证机制实现高精度电量估算)
  • RK3568 NPU :RKNN-ToolKit2环境搭建
  • Dify插件安装
  • 闪电科创,深度学习辅导
  • Linux-文本三剑客(grep、sed、awk)
  • 桥接模式,打造灵活可扩展的日志系统C++
  • 12-SpringBoot用户列表渲染案例
  • 多语言编码Agent解决方案(3)-VSCode扩展实现
  • 服务器装机遇到的问题
  • 【Linux】进程概念(下)
  • 流行的前端架构与后端架构介绍(Architecture)