刷题
 
 | # 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循环遍历客户端列表,删除超时记录、
 