# epoll模型核心要点
## 1. epoll核心概念
### 1.1 高效IO多路复用
- 监视列表与激活列表分离
- 内核使用红黑树存储描述符
- 边缘触发模式(EPOLLET)支持
### 1.2 事件触发机制
- **水平触发(LT)**:
- 默认模式,类似select/poll
- 数据未读完持续触发事件
- **边缘触发(ET)**:
- 需手动设置EPOLLET标志
- 数据到达仅触发一次事件
- 必须搭配非阻塞IO使用
## 2. 关键操作函数
### 2.1 epoll_create1
```c
int epfd = epoll_create1(EPOLL_CLOEXEC);
创建epoll实例 EPOLL_CLOEXEC标志自动关闭文件描述符
2.2 epoll_ctl
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
操作类型:
EPOLL_CTL_ADD 添加描述符 EPOLL_CTL_MOD 修改事件 EPOLL_CTL_DEL 删除描述符 事件结构体:
struct epoll_event {
uint32_t events; // EPOLLIN/EPOLLOUT/EPOLLERR
epoll_data_t data; // 携带用户数据
};
2.3 epoll_wait
int num = epoll_wait(epfd, events, maxevents, timeout);
阻塞等待事件触发 参数:
timeout=-1永久阻塞 timeout=0非阻塞 返回激活事件数量
3. 服务器实现流程
3.1 初始化阶段
// 创建TCP套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
// 绑定地址
bind(sfd, (struct sockaddr*)&addr, sizeof(addr));
// 设置监听队列
listen(sfd, 5);
// 创建epoll实例
int epfd = epoll_create1(EPOLL_CLOEXEC);
3.2 事件处理循环
接受新连接 :
int client_fd = accept(sfd, ...);
// 设置非阻塞模式
fcntl(client_fd, F_SETFL, O_NONBLOCK);
// 添加至epoll监视
epoll_ctl(epfd, EPOLL_CTL_ADD, client_fd, &event);
处理数据接收 :
while(recv() > 0) { // 边缘触发需循环读取
printf("Received: %s", buf);
if(errno == EAGAIN) break; // 非阻塞模式退出条件
}
异常处理 :
if(ret == 0) { // 客户端关闭
epoll_ctl(epfd, EPOLL_CTL_DEL, fd_temp, NULL);
close(fd_temp);
}
4. 模型对比
特性 select poll epoll 数据结构 位图(1024限制) 结构体数组 红黑树 时间复杂度 O(n)线性扫描 O(n)线性扫描 O(1)回调通知 触发模式 仅水平触发 仅水平触发 支持边缘触发 内存拷贝 每次全量复制 每次全量复制 增量操作 适用场景 低并发/跨平台 中等并发 高并发/Linux专用
5. 客户端实现要点
5.1 非阻塞IO设置
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
5.2 数据发送处理
while(1) {
fgets(buf, sizeof(buf), stdin);
send(sfd, buf, strlen(buf), 0); // 边缘触发需保证完全发送
if(errno == EAGAIN) usleep(1000); // 流量控制
}
6. 特殊场景处理
6.1 多客户端通信
服务端维护客户端映射表 使用epoll_data携带会话上下文
event.data.ptr = &client_ctx; // 传递自定义数据结构
6.2 心跳检测机制
定时器队列管理连接状态 EPOLLERR事件处理异常断开
# UDP套接字通信核心要点
## 1. UDP协议特性
### 基础特征
- 无连接不可靠传输
- 数据报独立发送
- 支持数据顺序错乱
- 效率高延迟低
### 适用场景
- 实时音视频传输
- 在线游戏数据交互
- 广播/组播通信
## 2. 核心函数解析
### socket创建
```c
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
协议族必须为AF_INET 类型指定SOCK_DGRAM
数据接收
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
数据发送
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
connect特殊用法
内核预存目标地址信息 允许使用send/recv简化调用 可多次调用更改目标地址
3. 服务器实现流程
核心步骤
创建DGRAM类型套接字 绑定固定IP和端口 循环接收客户端消息 响应消息附加处理标识
关键代码段
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
ret = recvfrom(sockfd, buf, sizeof(buf), 0,
(struct sockaddr*)&cliaddr, &len);
sendto(sockfd, modified_buf, strlen(modified_buf), 0,
(struct sockaddr*)&cliaddr, len);
4. 客户端实现模式
基础版本
高效版本
connect(sockfd, (struct sockaddr*)&seraddr, sizeof(seraddr));
send(sockfd, buf, strlen(buf), 0);
5. 特殊处理机制
地址重置
struct sockaddr_in unspec = { .sin_family = AF_UNSPEC };
connect(sockfd, (struct sockaddr*)&unspec, sizeof(unspec));
错误检测
recvfrom返回0表示空数据包 errno==EAGAIN时处理非阻塞状态 发送失败需重试或记录日志
6. 与TCP对比差异
特性 UDP TCP 连接方式 无连接 三次握手建立连接 数据边界 保留报文边界 字节流形式 可靠性 不保证数据完整 可靠传输 资源消耗 低 高 适用场景 实时性要求高的场景 数据完整性场景
7. 性能优化方向
使用连接式UDP减少系统调用 设置SO_RCVBUF/SO_SNDBUF 采用非阻塞IO+epoll多路复用 实现应用层重传机制