服务器连接多客户端

news2025/12/18 2:52:49

一、epoll 核心函数详解

1. epoll_create/epoll_create1 - 创建 epoll 实例

c

#include <sys/epoll.h>
int epoll_create(int size); // Linux 2.6.8前需指定size(>=1),后续版本可忽略
int epoll_create1(int flags); // 推荐使用,支持flags参数

  • 功能:创建一个 epoll 实例,返回文件描述符(epfd),用于管理监视的文件描述符。
  • 参数
    • size:旧版本需指定预分配大小(无实际作用,可设为 1)。
    • flags
      • 0:与epoll_create功能相同。
      • EPOLL_CLOEXEC:使 epfd 在进程 fork 时自动关闭。
  • 返回值:成功返回 epfd(非负整数),失败返回-1并置errno
  • 示例

    c

    int epfd = epoll_create1(EPOLL_CLOEXEC); // 创建带自动关闭功能的epoll实例
    
2. epoll_ctl - 管理监视列表

c

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

  • 功能:向 epoll 实例中添加、修改或删除监视的文件描述符及其事件。
  • 参数
    • epfd:epoll 实例的文件描述符。
    • op:操作类型:
      • EPOLL_CTL_ADD:添加文件描述符fd到监视列表。
      • EPOLL_CTL_MOD:修改fd关联的事件。
      • EPOLL_CTL_DEL:从监视列表删除fdevent参数可置NULL)。
    • fd:需操作的文件描述符(如套接字)。
    • event:指向epoll_event结构体的指针,包含监视事件和用户数据:

      c

      struct epoll_event {
          uint32_t events;       // 监视事件(如EPOLLIN、EPOLLOUT、EPOLLET)
          epoll_data_t data;     // 用户数据(如fd、指针等)
      };
      typedef union epoll_data {
          void        *ptr;      // 自定义指针
          int          fd;       // 监视的文件描述符
          uint32_t     u32;      // 32位整数
          uint64_t     u64;      // 64位整数
      } epoll_data_t;
      
  • 返回值:成功返回0,失败返回-1并置errno
  • 示例

    c

    struct epoll_event event;
    event.events = EPOLLIN | EPOLLET; // 边缘触发模式 + 读事件
    event.data.fd = sockfd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event); // 添加套接字到监视列表
    
3. epoll_wait - 等待事件触发

c

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

  • 功能:阻塞等待 epoll 实例中监视的文件描述符触发事件,返回激活的事件列表。
  • 参数
    • epfd:epoll 实例的文件描述符。
    • events:用于存储激活事件的结构体数组。
    • maxeventsevents数组的最大长度(需小于等于创建时的预分配值)。
    • timeout:超时时间(ms):
      • -1:永久阻塞,直到事件触发。
      • 0:非阻塞,立即返回。
      • >0:超时时间,到期后返回。
  • 返回值
    • >0:激活的事件数量(events中有效元素个数)。
    • 0:超时且无事件触发。
    • -1:失败并置errno
  • 示例

    c

    struct epoll_event events[1024];
    int n = epoll_wait(epfd, events, sizeof(events)/sizeof(events[0]), -1); // 永久阻塞等待事件
    for (int i = 0; i < n; i++) {
        int fd = events[i].data.fd;
        // 处理事件...
    }
    

二、epoll 工作原理

  1. 数据结构
    • 监视列表:使用红黑树存储所有监视的文件描述符,支持快速增删改查(时间复杂度 O (logN))。
    • 激活列表:使用链表或动态数组存储当前触发事件的文件描述符,避免遍历整个红黑树。
  2. 事件触发流程
    1. 通过epoll_ctl将文件描述符添加到红黑树(监视列表)。
    2. 内核监听文件描述符状态,当事件(如可读、可写)发生时,将其加入激活列表。
    3. epoll_wait返回激活列表中的事件,用户空间处理后,激活列表清空。

三、LT(水平触发)与 ET(边缘触发)模式对比

特性LT(水平触发)ET(边缘触发)
触发条件只要内核缓冲区有数据未读 / 未写,就持续触发事件。仅在状态变化时触发一次事件(如数据从无到有)。
读操作允许分多次读取,剩余数据会再次触发事件。必须一次性读完所有数据(需配合非阻塞 I/O),否则剩余数据不再触发。
写操作只要内核缓冲区有空间,就持续触发可写事件。仅在缓冲区由满变空时触发一次可写事件。
编程复杂度低,类似 select/poll,无需处理非阻塞。高,必须使用非阻塞 I/O,避免阻塞导致事件丢失。
适用场景简单场景、低速设备或不确定数据量的场景。高并发、高速数据传输场景(如 Web 服务器、实时通信)。

  • 示例配置

    c

    // LT模式(默认,无需指定EPOLLET)
    event.events = EPOLLIN; 
    
    // ET模式(需显式指定EPOLLET)
    event.events = EPOLLIN | EPOLLET; 
    

四、select/poll/epoll 对比(面试重点)

特性selectpollepoll
数据结构位图(数组),最大连接数受限于FD_SETSIZE(默认 1024)。结构体数组,理论无连接数限制(仅受内存限制)。红黑树 + 激活列表,支持上万级连接(如 10,000+)。
内核遍历方式每次调用遍历所有监视的文件描述符(O (n))。每次调用遍历所有监视的文件描述符(O (n))。仅遍历激活列表中的文件描述符(O (1)~O (k),k 为激活数)。
用户态 / 内核态数据拷贝每次select需拷贝全量文件描述符到内核。每次poll需拷贝全量文件描述符到内核。仅在epoll_ctl时更新红黑树,epoll_wait无需拷贝。
触发模式仅支持 LT 模式。仅支持 LT 模式。支持 LT 和 ET 模式。
跨平台性支持(Linux/Windows/macOS)。支持(Linux/UNIX)。仅 Linux 支持。
适用场景低并发、跨平台场景(如嵌入式)。中等并发场景。高并发、Linux 服务器场景(如 Nginx、Redis)。

五、epoll 服务器示例代码关键点(C 语言)

c

// 1. 创建epoll实例并设置监听套接字为非阻塞
int epfd = epoll_create1(EPOLL_CLOEXEC);
set_nonblocking(listen_fd); // 自定义函数,通过fcntl设置O_NONBLOCK

// 2. 注册监听套接字到epoll(ET模式)
struct epoll_event event = {
    .events = EPOLLIN | EPOLLET,
    .data = {.fd = listen_fd}
};
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &event);

// 3. 处理新连接(ET模式下需循环accept直到EAGAIN)
if (fd == listen_fd) {
    while (1) {
        int connfd = accept(listen_fd, &cliaddr, &addrlen);
        if (connfd == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) break; // 无新连接
            perror("accept");
            exit(EXIT_FAILURE);
        }
        set_nonblocking(connfd); // 客户端套接字也需设为非阻塞
        epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &event); // 注册读事件(ET模式)
    }
}

// 4. 处理读事件(ET模式下需循环recv直到EAGAIN)
else {
    char buf[BUFFER_SIZE];
    while (1) {
        ssize_t n = recv(fd, buf, sizeof(buf), 0);
        if (n == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) break; // 数据读完
            perror("recv");
            close(fd);
            epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
            break;
        } else if (n == 0) { // 客户端关闭连接
            close(fd);
            epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
            break;
        }
        // 处理数据...
    }
}

六、总结

  • epoll 优势
    • 高并发:基于红黑树和激活列表,适合管理上万级连接。
    • 高性能:事件通知复杂度 O (1),减少 CPU 消耗。
    • 灵活性:支持 LT/ET 模式,适配不同场景。
  • 使用建议
    • 高并发服务器首选 epoll,配合 ET 模式和非阻塞 I/O。
    • 简单场景或跨平台需求使用 select/poll。
    • 注意设置文件描述符非阻塞,避免 ET 模式下的数据丢失。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2378670.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于QT和FFmpeg实现自己的视频播放器FFMediaPlayer(一)——项目总览

在音视频开发的学习过程中&#xff0c;开发一款视频播放器是FFmpeg进阶的最好实战方法。本文将基于 QT 和 FFmpeg 着手实现自定义视频播放器 FFMediaPlayer&#xff0c;作为系列文章的开篇&#xff0c;我们先来整体了解项目的设计思路、架构与配置。 一、软件设计五大原则​ …

【HCIA】浮动路由

前言 我们通常会在出口路由器配置静态路由去规定流量进入互联网默认应该去往哪里。那么&#xff0c;如果有两个运营商的路由器都能为我们提供上网服务&#xff0c;我们应该如何配置默认路由呢&#xff1f;浮动路由又是怎么一回事呢&#xff1f; 文章目录 前言1. 网络拓扑图2. …

使用instance着色

本节我们学习使用instance着色器进行着色 //拾取var handler new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);handler.setInputAction(function(movement){console.log(movement);var pickedObject viewer.scene.pick(movement.position);if(Cesium.defined(picke…

【NLP 72、Prompt、Agent、MCP、function calling】

命运把我们带到哪里&#xff0c;就是哪里 —— 25.5.13 一、Prompt 1.User Prompt 用户提示词 当我们与大模型进行对话时&#xff0c;我们向大模型发送的消息&#xff0c;称作User Prompt&#xff0c;也就是用户提示词&#xff0c;一般就是我们提出的问题或者想说的话 但是我们…

Mysql数据库之集群进阶

一、日志管理 5.7版本自定义路径时的文件需要自己提前创建好文件&#xff0c;不会自动创建&#xff0c;否则启动mysql会报错 错误日志 rpm包(yum) /var/log/mysql.log 默认错误日志 ###查询日志路径 [rootdb01 ~]# mysqladmin -uroot -pEgon123 variables | grep -w log_e…

临床决策支持系统的提示工程优化路径深度解析

引言 随着人工智能技术在医疗领域的迅猛发展,临床决策支持系统(CDSS)正经历从传统规则引擎向智能提示工程的范式转变。在这一背景下,如何构建既符合循证医学原则又能适应个体化医疗需求的CDSS成为医学人工智能领域的核心挑战。本报告深入剖析了临床决策支持系统中提示工程的…

苹果新一代车载系统CarPlay Ultra来袭,全屏接管+ChatGPT助力,智能驾驶要“起飞”

AITOP100获悉&#xff0c;苹果又搞出大动作啦&#xff01;正式推出了新一代车载系统——CarPlay Ultra。这次&#xff0c;苹果可是下了狠功夫&#xff0c;把iPhone和汽车的所有显示屏深度整合到了一起&#xff0c;还首次把ChatGPT引入到了驾驶体验当中。这系统可不简单&#xf…

无线信道的噪声与干扰

目录 1. 无线信道(wireless channel)与电磁波 2.1 电磁波的传输(无线信道传输) 2.2 视线(line of sight)传播与天线高度 2. 信道的数学模型 2.1 调制信道模型 2.1.1 加性噪声/加性干扰 2.1.2 乘性噪声/乘性干扰 2.1.3 随参信道/恒参信道 2.2 编码信道模型 2.3 小结 …

MySQL 8.0 OCP 1Z0-908 101-110题

Q101.which two queries are examples of successful SQL injection attacks? A.SELECT id, name FROM backup_before WHERE name‘; DROP TABLE injection; --’; B. SELECT id, name FROM user WHERE id23 oR id32 OR 11; C. SELECT id, name FROM user WHERE user.id (SEL…

BBR 的 buffer 动力学观感

这周很忙&#xff0c;今天还加了一天班&#xff0c;但还是抽空实现了五一在安徽泾县山区喝着一壶酒写的 BBR ProbeRTT 的想法&#xff0c;没多少行代码&#xff0c;它真就消除了带宽锯齿&#xff0c;皮了个鞋&#x1f45e;&#xff0c;昨天我还在群里说了今天再说说 BBR 的&…

Spring之Bean的初始化 Bean的生命周期 全站式解析

目录 导图 步骤 第一步 实例化 第二步 属性赋值 第三步 初始化 aware 接口 BeanPostProcessor 接口 InitializingBean 和 init-method 第四步使用 第五步使用后销毁 描述一下 Bean 的 生命周期 导图 步骤 总体上可以分为五步 首先是 Bean 的实例化Bean 在进行实例…

FreeCAD源码分析: Transaction实现原理

本文阐述FreeCAD中Transaction的实现原理。 注1&#xff1a;限于研究水平&#xff0c;分析难免不当&#xff0c;欢迎批评指正。 注2&#xff1a;文章内容会不定期更新。 一、概念 Ref. from What is a Transaction? A transaction is a group of operations that have the f…

flutter缓存网络视频到本地,可离线观看

记录一下解决问题的过程&#xff0c;希望自己以后可以参考看看&#xff0c;解决更多的问题。 需求&#xff1a;flutter 缓存网络视频文件&#xff0c;可离线观看。 解决&#xff1a; 1&#xff0c;flutter APP视频播放组件调整&#xff1b; 2&#xff0c;找到视频播放组件&a…

Kotlin 中 infix 关键字的原理和使用场景

在 Kotlin 中&#xff0c;使用 infix 关键字修饰的函数称为中缀函数&#xff0c;使用是可以省略 . 和 ()&#xff0c;允许以更自然&#xff08;类似自然语言&#xff09;的语法调用函数&#xff0c;这种特性可以使代码更具可读性。 1 infix 的原理 中缀函数必须满足以下条件&…

c++从入门到精通(五)--异常处理,命名空间,多继承与虚继承

异常处理 栈展开过程&#xff1a; 栈展开过程沿着嵌套函数的调用链不断查找&#xff0c;直到找到了与异常匹配的catch子句为止&#xff1b;也可能一直没找到匹配的catch&#xff0c;则退出主函数后查找过程终止。栈展开过程中的对象被自动销毁。 在栈展开的过程中&#xff0c…

gcc/g++常用参数

1.介绍 gcc用于编译c语言&#xff0c;g用于编译c 源代码生成可执行文件过程&#xff0c;预处理-编译-汇编-链接。https://zhuanlan.zhihu.com/p/476697014 2.常用参数说明 2.1编译过程控制 参数作用-oOutput&#xff0c;指定输出名字-cCompile&#xff0c;编译源文件生成对…

nginx配置之负载均衡

版权声明&#xff1a;原创作品&#xff0c;请勿转载&#xff01; 1.实验环境准备 准备3台linux服务器&#xff08;ubuntu和centos均可&#xff0c;本文使用centos7.9&#xff09;&#xff0c;两台web和一台负载均衡服务器&#xff0c;均安装nginx服务 主机名IP软件lb0110.0.0…

去年开发一款鸿蒙Next Os的window工具箱

持拖载多个鸿蒙应用 批量签名安装 运行 http://dl.lozn.top/lozn/HarmonySignAndFileManagerTool_2024-11-26.zip 同类型安卓工具箱以及其他软件下载地址汇总 http://dl.lozn.top/lozn/ 怎么个玩法呢&#xff0c;比如要启动某app, 拖载识别到包名 点启动他能主动读取包名 然后…

uniapp|实现获取手机摄像头权限,调用相机拍照实现人脸识别相似度对比,拍照保存至相册,多端兼容(APP/微信小程序)

基于uniapp以及微信小程序实现移动端人脸识别相似度对比,实现摄像头、相册权限获取、相机模块交互、第三方识别集成等功能,附完整代码。 目录 核心功能实现流程摄像头与相册权限申请权限拒绝后的引导策略摄像头调用拍照事件处理人脸识别集成图片预处理(Base64编码/压缩)调用…

JavaScript【7】BOM模型

1.概述&#xff1a; BOM&#xff08;Browser Object Model&#xff0c;浏览器对象模型&#xff09;是 JavaScript 中的一个重要概念&#xff0c;它提供了一系列对象来访问和操作浏览器的功能和信息。与 DOM&#xff08;Document Object Model&#xff09;主要关注文档结构不同&…