# epoll模型核心要点## 1. epoll核心概念### 1.1 高效IO多路复用- 监视列表与激活列表分离- 内核使用红黑树存储描述符- 边缘触发模式(EPOLLET)支持### 1.2 事件触发机制- **水平触发(LT)**:- 默认模式,类似select/poll- 数据未读完持续触发事件- **边缘触发(ET)**:- 需手动设置EPOLLET标志- 数据到达仅触发一次事件- 必须搭配非阻塞IO使用## 2. 关键操作函数### 2.1 epoll_create1```cint 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/EPOLLERRepoll_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创建```cint 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多路复用 实现应用层重传机制