当前位置: 首页 > article >正文

深入解析epoll ET模式与守护进程

引言在前面的文章中我们学习了 epoll 的基础用法和 LT 模式。本文将深入讲解两个重要主题epoll 的 ET 模式边缘触发模式的编程要点与完整实现守护进程Linux 后台服务进程的原理与编写规范ET 模式是 epoll 高性能的关键而守护进程是服务器程序的最终运行形态。两者都是 Linux 服务端开发的核心技能。第一部分ET 模式深入一、LT 与 ET 的本质区别二、ET 模式编程三要素三、fcntl 设置非阻塞#include fcntl.h #include errno.h /** * 将文件描述符设置为非阻塞模式 * 原理 * 1. 用 F_GETFL 获取描述符现有的标志位 * 2. 用按位或 (|) 加上 O_NONBLOCK 标志 * 3. 用 F_SETFL 将新标志设置回去 */ int set_nonblock(int fd) { int flags fcntl(fd, F_GETFL, 0); if (flags -1) { perror(fcntl F_GETFL error); return -1; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) -1) { perror(fcntl F_SETFL error); return -1; } return 0; }关键理解必须先用F_GETFL获取原有标志不能直接设置。因为原有标志中可能包含O_RDONLY、O_WRONLY等访问模式标志直接覆盖会导致描述符无法正常工作。四、ET 模式下的错误码判断#include errno.h // 非阻塞模式下recv 返回 -1 不一定是错误 // 需要检查 errno 来区分无数据可读和真正的错误 n recv(fd, buf, size, 0); if (n -1) { if (errno EAGAIN || errno EWOULDBLOCK) { // 非阻塞模式下数据已读完正常情况 // EAGAIN 和 EWOULDBLOCK 在 Linux 下值相同 break; } else { // 真正的错误 perror(recv error); close(fd); break; } }重要EAGAIN和EWOULDBLOCK在 Linux 下是同一个值但为了可移植性通常两个都检查。五、完整 ET 模式服务器#include stdio.h #include stdlib.h #include string.h #include unistd.h #include fcntl.h #include errno.h #include sys/socket.h #include netinet/in.h #include arpa/inet.h #include sys/epoll.h #define PORT 6000 #define MAX_EVENTS 10 #define BUFFER_SIZE 128 /* 设置非阻塞 */ int set_nonblock(int fd) { int flags fcntl(fd, F_GETFL, 0); if (flags -1) return -1; return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } /* 创建监听套接字 */ int create_listen_socket() { int fd socket(AF_INET, SOCK_STREAM, 0); if (fd -1) { perror(socket); return -1; } int opt 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt)); struct sockaddr_in addr {0}; addr.sin_family AF_INET; addr.sin_port htons(PORT); addr.sin_addr.s_addr htonl(INADDR_ANY); if (bind(fd, (struct sockaddr*)addr, sizeof(addr)) -1) { perror(bind); close(fd); return -1; } if (listen(fd, 5) -1) { perror(listen); close(fd); return -1; } printf(ET 模式服务器启动端口: %d\n, PORT); return fd; } /* 向 epoll 添加描述符ET模式 非阻塞 */ void epoll_add_et(int epfd, int fd) { set_nonblock(fd); // ② 必须设置为非阻塞 struct epoll_event ev; ev.events EPOLLIN | EPOLLET; // ① 开启 ET 模式 ev.data.fd fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, ev) -1) perror(epoll_ctl add); } /* ET 模式下的数据读取循环读到 EAGAIN */ void handle_et_read(int epfd, int fd) { char buffer[BUFFER_SIZE]; while (1) { // ③ 循环读取直到读完 int n recv(fd, buffer, BUFFER_SIZE - 1, 0); if (n 0) { buffer[n] \0; printf(收到 fd%d: %s\n, fd, buffer); send(fd, OK, 2, 0); } else if (n 0) { // 对端关闭连接 printf(客户端关闭 fd%d\n, fd); epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); close(fd); break; } else { // n -1需要判断 errno if (errno EAGAIN || errno EWOULDBLOCK) { // 数据已读完非阻塞正常返回 break; } else { // 真正的错误 perror(recv error); epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); close(fd); break; } } } } int main() { int listen_fd create_listen_socket(); if (listen_fd -1) exit(1); int epfd epoll_create(1); if (epfd -1) { perror(epoll_create); exit(1); } epoll_add_et(epfd, listen_fd); struct epoll_event evs[MAX_EVENTS]; while (1) { int n epoll_wait(epfd, evs, MAX_EVENTS, -1); if (n -1) { perror(epoll_wait); break; } for (int i 0; i n; i) { int fd evs[i].data.fd; if (fd listen_fd) { // 监听套接字就绪 while (1) { // accept 也需要循环ET 模式 int client_fd accept(listen_fd, NULL, NULL); if (client_fd -1) { if (errno EAGAIN) break; perror(accept); break; } printf(新连接: fd%d\n, client_fd); epoll_add_et(epfd, client_fd); } } else { // 客户端数据就绪 handle_et_read(epfd, fd); } } } close(listen_fd); close(epfd); return 0; }注意ET 模式下accept也需要循环调用直到返回EAGAIN因为多个连接可能同时到达但 epoll 只通知一次。第二部分守护进程一、什么是守护进程二、核心概念会话、进程组、终端概念说明会话 (Session)一个终端对应一个会话包含多个进程组会话首进程终端中的第一个进程通常是 bash其 PID 即 SID进程组一组相关进程的集合组长 PID 即 PGID组长进程进程组中第一个创建的进程三、守护进程创建步骤四、完整守护进程实现#include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include sys/stat.h #include time.h #include string.h /** * 创建守护进程 * 成功返回 0失败返回 -1 */ int daemonize() { // ① 第一次 fork退出父进程 pid_t pid fork(); if (pid 0) { return -1; } else if (pid 0) { exit(0); // 父进程退出 } // 现在子进程运行且不是进程组组长 // ② 创建新会话 if (setsid() -1) { return -1; } // 现在子进程是新会话的首进程 新进程组的组长 // 已经脱离原终端控制 // ③ 第二次 fork退出父进程确保不是会话首进程 pid fork(); if (pid 0) { return -1; } else if (pid 0) { exit(0); // 一级子进程退出 } // 现在二级子进程运行不是会话首进程无法获取控制终端 // ④ 切换工作目录到根目录 chdir(/); // ⑤ 清除文件权限掩码 umask(0); // ⑥ 关闭所有文件描述符 int maxfd getdtablesize(); // 获取描述符表大小 for (int i 0; i maxfd; i) { close(i); } // stdin(0)、stdout(1)、stderr(2) 都已被关闭 return 0; }五、守护进程日志写入守护进程没有终端调试信息必须写入日志文件/** * 守护进程主逻辑周期性写入时间到日志文件 */ int main() { // 创建守护进程 if (daemonize() -1) { exit(1); } // 守护进程主循环 while (1) { // 获取当前时间 time_t now time(NULL); struct tm* tm_info localtime(now); // 打开日志文件追加模式/tmp 对所有用户可写 FILE* fp fopen(/tmp/daemon.log, a); if (fp ! NULL) { // 写入格式化时间 fprintf(fp, 守护进程运行中: %s, asctime(tm_info)); fclose(fp); } // 休眠 5 秒 sleep(5); } return 0; }日志相关要点要点说明日志路径通常放在/var/log/或/tmp/打开模式a追加模式不覆盖历史记录时间格式asctime(localtime(now))获取可读时间实时查看tail -f /tmp/daemon.log动态监控六、面试常见问题问题答案要点为什么先 fork 再 setsidsetsid 要求调用进程不能是进程组组长。fork 后子进程不是组长满足条件为什么需要二次 fork第一次 forksetsid 后子进程成为会话首进程可能重新获取控制终端。二次 fork 后不再是会话首进程彻底杜绝为什么要 chdir(/)守护进程可能从 U 盘等目录启动切换到根目录避免占用可卸载的文件系统为什么要 umask(0)继承的 umask 可能限制文件权限清零确保守护进程创建文件时权限完全由 open 参数控制为什么要关闭所有 fd释放从父进程继承的无关描述符节省系统资源七、守护进程的查看与终止# 查看守护进程ps -ef | grep daemon_name# 查看进程的会话 IDps -eo pid,sid,comm | grep daemon_name# 终止守护进程只能通过 killkill PIDkill -9 PID # 强制终止# 实时查看日志tail -f /tmp/daemon.log总结一、ET 模式要点速查要素操作开启 ETev.events EPOLLIN | EPOLLET设置非阻塞fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)循环读取while(1) { recv() ... if(errnoEAGAIN) break; }accept 处理ET 下 accept 也需循环到 EAGAIN二、守护进程要点速查守护进程 两次 fork setsid chdir(/) umask(0) close(fd)第一次 fork → 子进程不是组长为 setsid 准备setsid() → 创建新会话脱离终端第二次 fork → 确保不是会话首进程chdir(/) → 切换工作目录umask(0) → 清除权限掩码close(fd) → 关闭所有文件描述符三、LT vs ET 选择场景推荐模式简单服务器、学习目的LT默认模式高并发、追求极致性能ET 模式大数据量传输ET减少系统调用快速原型开发LT编程简单

相关文章:

深入解析epoll ET模式与守护进程

引言在前面的文章中,我们学习了 epoll 的基础用法和 LT 模式。本文将深入讲解两个重要主题:epoll 的 ET 模式:边缘触发模式的编程要点与完整实现守护进程:Linux 后台服务进程的原理与编写规范ET 模式是 epoll 高性能的关键&#x…...

win10打印机不能共享报0x0000011b/0x00000709修复工具合集分享 ,亲测解决Windows打印机共享报错问题

先说说我的情况。公司大概十几个人,两台共享打印机,一台接在Win10的台式机上,一台接在Win11的笔记本上。本来用着一直正常,去年开始,陆陆续续有同事反映连不上打印机。 最常见的报错就是0x00000709,还有0x…...

拾亩绿光纯亚麻籽微粉效果怎么样

很多人想通过亚麻籽补充营养,却常遇到传统亚麻籽难吸收、营养易流失的问题:直接嚼咽口感粗糙,普通研磨粉冲调结块,榨油后Omega-3等核心营养大量损耗。拾亩绿光纯亚麻籽微粉依托南京国英健康科技有限公司的专利技术,可解…...

Windows 10 PL2303驱动修复终极指南:3种方案解决串口设备兼容性问题

Windows 10 PL2303驱动修复终极指南:3种方案解决串口设备兼容性问题 【免费下载链接】pl2303-win10 Windows 10 driver for end-of-life PL-2303 chipsets. 项目地址: https://gitcode.com/gh_mirrors/pl/pl2303-win10 PL2303驱动修复方案是解决Windows 10系…...

爆单实操课:从3C到美妆,跨境商家如何用AI神器搞定TikTok本土化

每天都有无数跨境卖家在各大社群里发问:怎么用ai生成带货视频,有哪些工具比较好用? 在 TikTok 这个极度依赖内容爆发的平台上,不同类目的产品对视频素材的需求千差万别。靠人工剪辑不仅效率低,且极难跨越本土化语言的障…...

语音真实度突破98.7%的关键在哪?ElevenLabs最新v3.2引擎深度测评,附权威MOS评分对比表

更多请点击: https://intelliparadigm.com 第一章:语音真实度突破98.7%的关键在哪?ElevenLabs最新v3.2引擎深度测评,附权威MOS评分对比表 ElevenLabs v3.2 引擎在2024年Q2发布的音频合成基准测试中,首次在自然度&…...

Sora 2如何“唤醒”3D Gaussian Splatting?:从神经辐射场到毫秒级动态场景生成的4层技术跃迁解析

更多请点击: https://intelliparadigm.com 第一章:Sora 2与3D Gaussian Splatting融合的范式革命 传统视频生成模型受限于体素网格或NeRF隐式表示的计算开销与几何保真度瓶颈,而Sora 2通过引入时空一致性token压缩机制,与3D Gaus…...

基于LLM的多智能体协作框架:从原理到实践构建自主开发团队

1. 项目概述与核心价值最近在开源社区里,一个名为zxkane/autonomous-dev-team的项目引起了我的注意。乍一看这个标题,你可能会联想到科幻电影里的全自动机器人编程,或者是一些过于理想化的“AI接管开发”的噱头。但在我花时间深入研究和实践之…...

PCI总线‘对话’的艺术:主从设备如何通过FRAME#、STOP#信号优雅地‘开始’与‘结束’传输

PCI总线‘对话’的艺术:主从设备如何通过FRAME#、STOP#信号优雅地‘开始’与‘结束’传输 在计算机系统的内部世界里,总线的数据传输就像一场精心编排的舞会。PCI总线作为这场舞会的舞台,主从设备之间的每一次交互都遵循着严格的礼仪规则。这…...

别再乱加电阻了!手把手教你用SI9000搞定PCB阻抗匹配(附50欧姆计算实例)

高速PCB设计实战:用SI9000精准计算阻抗匹配的工程方法 当信号频率突破百兆赫兹时,PCB走线就不再是简单的电气连接——它们变成了需要精密控制的传输线。去年参与一个千兆以太网项目时,我曾目睹团队因阻抗失配导致信号完整性崩溃的惨痛案例&am…...

音频变压器关键参数深度解析:Z值与最大电流的工程实践

音频变压器关键参数深度解析:Z值与最大电流的工程实践引言在专业音频系统、高保真音响以及工业信号隔离场景中,音频变压器始终扮演着不可替代的角色。它的核心使命是在保持信号完整性的同时,完成阻抗匹配、地环路隔离和信号平衡转换三大任务。…...

为AI智能体构建可编程邮箱:mailbot实战指南

1. 项目概述:为AI智能体打造专属的“可编程邮箱”如果你正在开发一个AI智能体,无论是客服机器人、自动化工作流还是个人助理,让它具备收发邮件的能力往往是刚需。传统的做法是什么?要么去折腾Gmail的API,忍受OAuth授权…...

3分钟掌握Krita AI抠图:点一下就能完成的智能选区革命

3分钟掌握Krita AI抠图:点一下就能完成的智能选区革命 【免费下载链接】krita-vision-tools Krita plugin which adds selection tools to mask objects with a single click, or by drawing a bounding box. 项目地址: https://gitcode.com/gh_mirrors/kr/krita-…...

百度文库文档免费下载终极指南:3步快速获取纯净PDF

百度文库文档免费下载终极指南:3步快速获取纯净PDF 【免费下载链接】baidu-wenku fetch the document for free 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wenku 你是否曾在百度文库找到心仪的文档,却被烦人的广告、付费提示和杂乱页面…...

【DeepSeek开发者垂直搜索实战指南】:3大行业落地案例+5个避坑要点,限时公开内部调优参数

更多请点击: https://intelliparadigm.com 第一章:DeepSeek开发者垂直搜索应用案例全景概览 DeepSeek系列大模型凭借其开源、高性能与强推理能力,正被广泛集成至开发者垂直搜索场景中——从代码片段检索、API文档语义查找,到私有…...

【力扣100题】22. 矩阵置零

一、题目描述 给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。 示例 1: 输入:matrix [[1,1,1],[1,0,1],[1,1,1]] 输出:[[1,0,1],[0,0,0],[1,0,1]]示例 2: …...

日本电子产业转型启示:从技术过剩到商业模式创新

1. 日本电子产业的十字路口:一场箱根闭门会背后的行业剧痛2013年的春天,当全球电子产业的聚光灯都打在硅谷和深圳时,日本箱根的一家温泉旅馆里,正进行着一场鲜为人知却意义深远的对话。索尼、瑞萨、NEC、日立、松下、富士通、Mega…...

AXI协议深度解析:从握手到低功耗,一次搞懂芯片内部数据流的那些“潜规则”

AXI协议深度解析:从握手到低功耗,一次搞懂芯片内部数据流的那些“潜规则” 在当今高性能计算和复杂SoC设计中,AXI协议已成为连接处理器、存储器和外设的黄金标准。但真正理解AXI的精髓,远不止于掌握基础操作——那些隐藏在规范字里…...

Excel数据同步ERP/CRM太麻烦?一个Python脚本搞定多系统自动填充(基于GoBot)

Excel数据同步ERP/CRM太麻烦?一个Python脚本搞定多系统自动填充(基于GoBot) 每次月底看着财务同事在ERP系统里逐条录入Excel数据,市场部同事又在CRM里重复同样的操作,这种低效场景你一定不陌生。数据在不同系统间的孤岛…...

告别桌面混乱!Ubuntu 16.04 多桌面+Terminator分屏,打造程序员高效工作流

Ubuntu 16.04多桌面与Terminator分屏:构建程序员的高效工作流 作为一名长期在Ubuntu环境下工作的开发者,我深刻体会到工作环境配置对效率的影响。桌面混乱、窗口堆叠、频繁切换不仅浪费时间,还会打断编程的"心流"状态。经过多次迭代…...

告别龟速下载!实测对比Axel、Aria2、mwget三大神器,教你选对多线程工具

三大命令行下载神器深度横评:Axel、Aria2与mwget的性能对决 当你在终端里反复输入wget或curl命令,盯着缓慢增长的进度条时,是否想过还有更高效的解决方案?本文将带你深入探索Axel、Aria2和mwget这三款命令行下载加速工具&#xff…...

MGRE实验报告

一.实验概述实验名称:MGRE实验实验目的:掌握 PPP 协议的 PAP/CHAP 认证与 HDLC 封装配置,理解不同广域网链路协议的工作机制与认证流程。实现 MGRE 环境(R1 为 Hub)与 GRE 环境的部署,理解点到多点 VPN 与点…...

DDR3内存训练(Training)完全解析:从原理到代码,深入浅出

DDR3内存训练(Training)完全解析:从原理到代码,深入浅出 目录 一、为什么需要内存训练? 二、DDR3训练的核心原理 三、训练流程详解:一场精密的三步仪式 四、代码实战:从初始化到训练完成...

C语言-指针二

一. 指针的操作int main() {int a 10 , b 20, c 30;int *p NULL, *q NULL;p &a;//对指针变量p本身进行修改b *p;//*p为右值表示对变量a的读取*p 60;//*p为左值表示通过指向的内存空间对变量a的写入p &c;//p指向的内存空间发生变化b *p;//对c的读取操作*p 70…...

iOS越狱防火墙ijfw:从网络流量监控到精细化应用管控实战

1. 项目概述与核心价值最近在折腾一个挺有意思的开源项目,叫ijfw,全称是iOS Jailbreak Firewall。顾名思义,这是一个专门为越狱后的iOS设备设计的防火墙工具。如果你和我一样,是个喜欢在iPhone上“折腾”的玩家,或者对…...

数据中心机架内互连新范式:为何PCIe正取代以太网与InfiniBand?

1. 数据中心互连的十字路口:为什么是PCIe?在数据中心这个庞大而精密的数字世界里,服务器、存储和网络设备之间的“对话”效率,直接决定了整个系统的性能上限。过去十几年,我们习惯了用以太网(Ethernet&…...

Windows下Python包管理权限踩坑实录:从WinError 5到WinError 32的完整解决流程

Windows下Python包管理权限问题深度解析:从WinError 5到WinError 32的实战指南 作为一名长期在Windows平台进行Python开发的工程师,我深刻理解文件权限问题带来的困扰。特别是当你在紧急项目交付前夜,突然遭遇PermissionError: [WinError 5]或…...

从五管OTA到两级运放:在Cadence IC617中如何规划你的设计指标与晶体管尺寸(gm/id方法详解)

从五管OTA到两级运放:gm/id设计方法在Cadence IC617中的策略性应用 在模拟集成电路设计中,运算放大器的设计始终是工程师面临的核心挑战之一。特别是当设计需求从简单的五管OTA扩展到更复杂的两级运放时,设计者需要处理的不仅仅是晶体管尺寸的…...

2026年医疗卫生/护理求职AI工具横评:白衣天使的求职神器大比拼

导语 2026年,医疗卫生行业依然是最具社会价值和就业稳定性的行业之一。随着中国老龄化加速,医护人员需求持续扩大,仅公立医院护士岗位需求量就突破200万。然而,医护求职并不轻松:编制紧张、规培政策复杂、职称考试压力…...

从零到一:在STM32F103上构建FatFs文件系统并驱动W25Q64 Flash

1. 硬件准备与环境搭建 在开始构建FatFs文件系统之前,我们需要先准备好硬件环境。我手头用的是STM32F103C8T6最小系统板,搭配一块W25Q64 Flash芯片。这块Flash芯片容量为8MB,通过SPI接口通信,正好适合用来做文件存储介质。 首先得…...