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

关于第一次接触Linux TCP/IP网络相关项目

1,IP地址和端口号

IP地址,好比哪一栋楼,告诉你在哪台机器;

port端口,好比哪一层住户,也就是机器上的哪个用户;

两个人聊天:

  • 聊天要有 电话机 (socket)

  • 聊天要有 听电话的方式 (阻塞/非阻塞、epoll 事件机制)

2,TCP、客户端、服务端

  • TCP:就像打电话,连接建立后,可以可靠、按顺序地说话,不会丢字。一个TCP连接需要:

    本地IP + 本地端口 ——> 远端IP + 远端端口

  • 客户端 (client):主动打电话的人(发起连接)。

  • 服务端 (server):等电话的人(被动等待)。

3,Socket(套接字)

  • socket 就是一部“电话机”,你要么用它来打电话,要么用它来接电话。

  • 在代码里,socket() 函数会给你一个 fd(文件描述符),就像一个电话句柄。

Linux 下万物皆文件,socket 也当作文件来处理,所以你能对它用 open/close, read/write, fcntl 等函数。

4,一个 TCP 服务端常见流程(框架)

服务端:

socket() // 买电话机 

bind() // 把电话机安装到你家某个门牌号(IP+端口) 

listen() // 开始等待电话 

accept() // 有人打电话进来,接起 

recv()/send() // 和对方说话 

close() // 挂电话

客户端:

socket() // 买电话机 

connect() // 拨号 (对方IP+端口) 

send()/recv() // 说话 

close() // 挂电话

5,事件驱动 epoll

假如你有 不止一个电话,要同时听怎么办?

  • 阻塞:你只能一心一意守着一个电话。recv() 会一直等到有数据,像电话响才接。

  • 非阻塞:recv() 如果没数据,直接返回,不等。

  • 轮询:傻傻的去问“有电话吗?有电话吗?”(效率低)。

  • epoll:Linux 提供的“秘书”,帮你同时监听很多电话(fd),只要有响铃(EPOLLIN/EPOLLOUT),秘书马上提醒你。这样你不用去问 socket 有没有数据,秘书会在有数据时告诉你。

相关操作:

  • epoll_create:雇个秘书。

  • epoll_ctl:告诉秘书你要盯哪些电话(fd)。

  • epoll_wait:让秘书帮你等,有电话就叫醒你。

那epoll_wait 等待的到底是啥?

epoll_wait(epoll_fd, events, MAX_EVENTS, -1) 本质上是:阻塞等候多个 fd 上的“状态变化”

所谓的“event”,就是 文件描述符(fd) 上发生的某种情况
常见的 event 类型:

  • EPOLLIN:可读(socket 收到数据 / 有新连接 / eventfd 有新数)

  • EPOLLOUT:可写(socket 发送缓冲区空闲了)

  • EPOLLERR:错误

所以:

  • client 有电话来了(发数据) → 对应 client_fd 上出现 EPOLLIN → epoll_wait 醒来,告诉你“这个 fd 有数据了”。

  • 有新连接 → 对应 server_fd 上出现 EPOLLIN → epoll_wait 醒来,告诉你“有新客户端要 accept”。

  • 你自己写了 eventfd → eventfd 上出现 EPOLLIN → epoll_wait 醒来,告诉你“eventfd 被触发了”。

结论:client 消息、新连接、eventfd 唤醒,本质都是“fd 上的状态变化(event)”,epoll_wait 统一帮你监控

6,eventfd

是一种特殊的 fd,它本质上就是一个小“计数器”。可以通过write(event_fd, &u, sizeof(u))往里面写一个数(比如 1),它就像按了一个“按钮”,当这个计数器大于 0 时,这个 fd 就会变成 可读(EPOLLIN)。你用 read(event_fd, &u, sizeof(u)) 把它读出来,计数器清零或减少。别人 epoll_wait 的时候会被唤醒,知道“有人按了按钮”。

所以 eventfd 的作用就是:让你自己也能制造一个“事件”,把它接入 epoll 体系

比喻:你在办公室打瞌睡(epoll_wait 阻塞中)。你队友过来敲一下桌子(写 eventfd)。你马上醒来(epoll_wait 返回),知道有新任务。

6.1,eventfd 和 server 有啥关系?

严格说:

  • eventfd 和 server 没有业务上的关系

  • 但是它是 server 内部机制的一部分,用来做 控制 / 通知 / 线程间通信

比如:

  • 你的 server 正在 epoll_wait() 里阻塞着

  • 你想优雅关闭 server → 你调用 stop() → 给 event_fd 写一个数

  • epoll_wait 被唤醒(就像有人打断秘书)

  • server 主循环读出 eventfd → 知道要退出

如果没有 eventfd,你就很难在 epoll_wait 阻塞时告诉它“该醒了”。

再也可以这样理解:

  • server_fd
    就像一个“门口的门铃”。有新客户端来敲门,epoll 就会告诉主循环去 accept()

  • event_fd
    就像“老板有急事按的紧急电话”。即使没有客户端消息,也能让 epoll_wait() 马上醒来执行。比如,stop() 就是写 1 到 eventfd → 让主循环退出。

类比:

  • socket 的“事件”是 客户端发数据

  • eventfd 的“事件”是 你自己写进去的数字

  • epoll 不管 fd 是 socket 还是 eventfd,反正都是“fd 上有事儿了”

6.2,eventfd 使用的 API

典型使用流程:

// 1. 创建 eventfd 

int efd = eventfd(0, EFD_NONBLOCK); 

// 2. 加入 epoll 监听 

struct epoll_event ev{}; 

ev.events = EPOLLIN; // 等它可读 

ev.data.fd = efd; 

epoll_ctl(epoll_fd, EPOLL_CTL_ADD, efd, &ev); 

// 3. 在别的地方写入,触发事件

uint64_t u = 1; 

write(efd, &u, sizeof(uint64_t)); 

// 4. epoll_wait 被唤醒后,你在主循环里处理

if (fd == efd) {

uint64_t v; 

read(efd, &v, sizeof(uint64_t)); 

// 把数读出来 

std::cout << "eventfd triggered, value=" << v << std::endl; 

}

👉 这样,eventfd 就和 server 的 epoll 主循环挂上了钩。


6.3,整体关系再捋一下

  • server_fd:监听新连接

  • client_fd:收/发客户端消息

  • eventfd:给自己用的“内部通知器”,比如唤醒 server 停止、线程通信等

  • epoll:秘书,统一盯着所有 fd 的状态变化(server_fd/client_fd/eventfd)


6.4,类比总结

  • socket 就像 客户电话,客户打来你就得接。

  • eventfd 就像 老板的内线电话,不是客户,但可以随时打断你。

  • epoll_wait 就像 前台秘书,她同时帮你盯着客户电话和老板内线,哪个响了都立刻告诉你。

  • server 主循环:秘书报告后,你去决定是接客户电话还是听老板指示。

7,setsockopt, fcntl, keepalive

  • setsockopt:给 socket 调调参数,比如:

    • 开启 TCP keepalive(让系统定期发心跳包,防止对方死了你还蒙在鼓里)。

    • 设置收发缓冲区大小。

  • fcntl:修改 fd 的属性,比如把 socket 设置成 非阻塞(打电话时不必傻等,可以先去干别的事)。

8. recv / send / open / close

  • recv:接收数据(别人说的话)。

  • send:发送数据(你说话)。

  • open/close:打开/关闭一个“文件”或者“设备”,socket 也走这套接口。

9. 整个常见框架(Server + Clients)

把这些拼起来,一个典型的 Linux 网络编程模型

  1. Server 进程:

    • socket → bind → listen

    • epoll_create(雇秘书)

    • epoll_ctl(秘书盯着监听 socket + 已连接的 socket)

    • epoll_wait(秘书等电话)

    • accept() 接来电,recv/send 聊天

  2. Client 进程:

    • socket → connect → send/recv

    • 挂掉时 close

  3. 多线程/多进程:

    • 可以一个线程专门负责 epoll_wait

    • 收到数据后丢给 worker 线程处理

10,运行流程

  1. server 启动 → server_fd 加入 epoll

  2. 新客户端连进来 → server_fd 上有事件 → accept() → 得到 client_fd

  3. 客户端发消息 → client_fd 上有事件 → recv() → 丢给线程池处理 → 回包

  4. 如果主程序要退出 → stop()event_fd1 → epoll_wait 被唤醒 → runLoop 退出

http://www.lryc.cn/news/623714.html

相关文章:

  • 使用Ansys Fluent进行倒装芯片封装Theta-JA热阻表征
  • 计算机网络 OSI 七层模型和 TCP 五层模型
  • IP 分片和组装的具体过程
  • 数字货币的法律属性与监管完善路径探析
  • Trae 辅助下的 uni-app 跨端小程序工程化开发实践分享
  • 【Java后端】Spring Boot 集成 MyBatis-Plus 全攻略
  • 【昇腾】单张48G Atlas 300I Duo推理卡MindIE+WebUI方式跑14B大语言模型_20250817
  • 前端vue3+后端spring boot导出数据
  • Java 大视界 -- Java 大数据分布式计算在基因测序数据分析与精准医疗中的应用(400)
  • Linux | i.MX6ULL网络通信-套字节 UDP(第十八章)
  • 计算机网络 TCP 延迟确认机制
  • 矿物分类案列 (一)六种方法对数据的填充
  • 安卓开发者自学鸿蒙开发2页面高级技巧
  • 安卓14系统应用收不到开机广播
  • Android原生(Kotlin)与Flutter混合开发 - 设备控制与状态同步解决方案
  • Javascript面试题及详细答案150道之(106-120)
  • Python实现区域生长和RANSAC聚类
  • 职场新人如何在快速适应工作的同时保持自我成长节奏?
  • JUC常用线程辅助类详解
  • JavaScript 性能优化实战大纲
  • [GLM-4.5] LLM推理服务器(SGLang/vLLM) | 工具与推理解析器
  • c_str()函数的详细解析
  • 【PHP】Hyperf:接入 Nacos
  • Python | 解决 matplotlib 中文乱码
  • 基于MATLAB多智能体强化学习的出租车资源配置优化系统设计与实现
  • [论文阅读] 人工智能 + 职业教育 | 从技能操作者到技术反思者:生成式AI驱动职业教育学习范式转型
  • 豆包 Java的23种设计模式
  • 微调 AnomalyCLIP——基于对象无关提示学习与全局 - 局部优化的零样本异常检测框架性能验证
  • 迅速掌握Git通用指令
  • 7 索引的监控