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

关于第一次接触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.xdnf.cn/news/18221.html

相关文章:

  • Docker入门:容器化技术的第一堂课
  • python---装饰器
  • 在线编程题目之小试牛刀
  • [每周一更]-(第155期):Go 1.25 发布:新特性、技术思考与 Go vs Rust 竞争格局分析
  • 回溯剪枝的 “减法艺术”:化解超时危机的 “救命稻草”(一)
  • 机器学习算法篇(十三)------词向量转化的算法思想详解与基于词向量转换的文本数据处理的好评差评分类实战(NPL基础实战)
  • 微服务之间的调用需要走网关么?
  • Linux Shell定时检查日期执行Python脚本
  • Python数据类型转换详解:从基础到实践
  • uniappx 安卓端本地打包的一些总结
  • 【typenum】 16 非零标记及改进建议
  • 【Linux系统】动静态库的制作
  • java之 junit4单元测试Mockito的使用
  • Pycharm Debug详解
  • 深度学习之优化器
  • 数据与模型融合波士顿房价回归建模预测
  • 数据结构(排序篇)——七大排序算法奇幻之旅:从扑克牌到百亿数据的魔法整理术
  • LeetCode 1323: 6和9组成的最大数字
  • 内网后渗透攻击--隐藏通信隧道技术(应用层隧道技术)
  • 一键管理 StarRocks:简化集群的启动、停止与状态查看
  • JAVA后端开发——Token自动续期机制的必要性
  • 库制作与原理(下)
  • RabbitMQ面试精讲 Day 24:消费者限流与批量处理
  • Linux中iSCSI存储配置与管理指南
  • Leetcode 15 java
  • 【LeetCode 热题 100】118. 杨辉三角
  • 使用Github Page发布网站
  • Compose笔记(四十六)--Popup
  • 廖雪峰-java教程-Part01
  • RK3588开发板Ubuntu系统烧录