刷题
| # UDP多点通信核心要点 |
| |
| ## 基础通信模式 |
| ### 单播通信 |
| - 一对一通信方式 |
| - UDP默认通信模式 |
| - 地址指向具体目标主机 |
| |
| ### 广播通信 |
| - 一对多通信机制 |
| - 地址范围:`xxx.xxx.xxx.255` |
| - 仅限局域网传输 |
| - 需设置SO_BROADCAST标志 |
| |
| ### 组播通信 |
| - 多对多群组通信 |
| - 地址范围:224.0.0.0~239.255.255.255 |
| - 需加入组播IP(IP_ADD_MEMBERSHIP) |
| |
| ## 核心函数配置 |
| ### setsockopt参数 |
| #### 通用配置 |
| - `SO_REUSEADDR`:端口复用 |
| - `SO_RCVTIMEO`:接收超时 |
| - `SO_SNDTIMEO`:发送超时 |
| |
| #### 广播配置 |
| - `SO_BROADCAST`:广播权限 |
| - 绑定地址:`255.255.255.255` |
| |
| #### 组播配置 |
| - `IP_ADD_MEMBERSHIP`:加入组播 |
| - `struct ip_mreqn`结构体: |
| ```c |
| struct ip_mreqn { |
| struct in_addr imr_multiaddr; // 组播IP |
| struct in_addr imr_address; // 本地IP |
| int imr_ifindex; // 网络接口索引 |
| }; |
通信实现逻辑
广播服务器
- 创建DGRAM套接字
- 绑定广播地址或
0.0.0.0
- 设置
SO_REUSEADDR
- 循环接收数据
组播客户端
- 创建DGRAM套接字
- 加入组播组(IP_ADD_MEMBERSHIP)
- 绑定组播IP地址
- 接收群组消息
特殊处理机制
超时控制
- 接收超时结构体:
| struct timeval { |
| __kernel_time_t tv_sec; // 秒 |
| __kernel_suseconds_t tv_usec; // 微秒 |
| }; |
错误检测
- 返回值检测:
recvfrom
返回0表示空数据包EAGAIN
错误处理非阻塞状态- 发送失败重试机制
通信限制对比
特性 | 单播 | 广播 | 组播 |
---|
地址范围 | 具体IP | 255结尾地址 | 224-239网段 |
跨路由器 | 支持 | 不支持 | 支持 |
适用场景 | 精准传输 | 局域网通知 | 群组通信 |
资源消耗 | 低 | 高 | 中等 |
代码结构示例
组播接收端
| // 加入组播组 |
| struct ip_mreqn mreq; |
| mreq.imr_multiaddr.s_addr = inet_addr("224.1.2.3"); |
| mreq.imr_address.s_addr = inet_addr("192.168.1.100"); |
| mreq.imr_ifindex = 0; |
| setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); |
广播发送端
| // 启用广播权限 |
| int broadcast = 1; |
| setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); |

| # 心跳包核心要点 |
| |
| ## 基本概念 |
| - **定义**:用于维持长连接的活跃状态,防止网络设备断开空闲连接 |
| - **核心目的**: |
| - 检测客户端存活状态 |
| - 避免防火墙/NAT误判连接失效 |
| |
| ## 实现机制 |
| ### 时间戳维护 |
| - **客户端**:发送业务消息或心跳包时更新最后通信时间 |
| - **服务端**: |
| - 接收消息后更新时间戳 |
| - 维护客户端列表(IP+Port+最后通信时间) |
| |
| ### 心跳包发送 |
| - **周期触发**:客户端每30秒发送空数据包 |
| - **信号机制**: |
| ```c |
| signal(SIGALRM, handler); // 注册ALRM信号处理函数 |
| alarm(5); // 每5秒触发信号 |
超时检测
- 定时任务:服务端每秒检查时间差
- 超时阈值:60秒无通信判定离线
- 清理逻辑:
| if(time(NULL) - tm > 4) { |
| 删除客户端记录 |
| } |
关键函数
时间处理
- time():获取1970年至今秒数
- localtime():转换时间戳为tm结构体
- strftime():格式化时间输出(如"%Y-%m-%d %H:%M:%S")
网络通信
- recvfrom():接收UDP数据包
- sendto():发送心跳包或业务数据
数据结构
消息类型
enum type_t { CHAR, HEART }; // CHAR=业务消息,HEART=心跳包
消息结构体
| typedef struct msgbuf { |
| enum type_t type; // 消息类型 |
| char text[128]; // 消息内容 |
| } msgbuf_t; |
客户端状态记录
| typedef struct timebuf { |
| unsigned int ip; // 客户端IP |
| unsigned short port;// 端口号 |
| time_t tm; // 最后通信时间 |
| } timebuf_t; |
代码结构
服务端逻辑
- 创建UDP套接字并绑定端口
- 启动独立线程检测超时客户端
- 接收消息后分类处理:
- CHAR类型:更新通信时间并处理业务
- HEART类型:仅更新时间戳
客户端逻辑
- 创建UDP套接字连接服务端
- 设置定时器发送心跳包:
| handler() { |
| sendto(HEART包); |
| alarm(5); // 重置5秒定时 |
| } |
多线程处理
- 超时检测线程:
| pthread_create(&thread, NULL, cli_delete, NULL); |
| pthread_detach(thread); // 分离线程 |
- 清理逻辑:
- for循环遍历客户端列表,删除超时记录、
