1.9 搞清楚Socket

沿 socket 端点、绑定监听、连接建立、字节收发和关闭回收追踪文件描述符与连接状态。

学习目标

  • 能沿创建端点、绑定监听、建立连接、收发字节和关闭回收追踪 socket 生命周期
  • 能区分监听 socket、accept 返回的已连接 socket、文件描述符和连接五元组
  • 能在积压、短读、对端关闭和描述符泄漏场景中定位首个状态偏离并重放

1.9 搞清楚Socket

本页依据刘欣《码农翻身》(2018 年第 1 版)及出版社公开书目信息,独立重构 1.9 搞清楚Socket。正文、代码、图示、实验和练习都是本课程重新设计的教学材料,不复制原书正文、插图、练习答案或代码。

socket 是进程进入网络协议栈的端点接口,不是“网络上的一根管子”。服务器通常创建 socket、bind 地址、listen、accept 连接;客户端创建 socket、connect,然后双方通过已连接端点读写字节。监听端点和每个已连接端点有不同的状态、文件描述符和回收责任。

三个会让 socket 模型失真的陷阱

socket 端点合同

不是把 socket 拟人化,而是要求每个 fd 都能回答它属于哪个进程、处于什么状态、关联哪个五元组、能读写什么以及由谁关闭。

连接身份可写成:

connection=(srcIP,srcPort,dstIP,dstPort,protocol)connection=(srcIP,srcPort,dstIP,dstPort,protocol)

五元组区分连接身份,但不替代 fd 生命周期。监听 socket 可以对应多个 accept 返回的连接 fd;同一连接的读写也可能因短读、缓冲和关闭方向进入多个状态。

socket 生命周期:监听端点与连接端点分开验收fd、五元组、字节缓冲和关闭方向共同定义连接状态1创建端点fd + 类型状态证据2绑定监听地址 + 队列监听边界3建立连接五元组连接边界4收发字节缓冲 + 帧状态证据5关闭连接EOF + 回收状态证据close 本地成功不等于对端处理完成,也不等于所有 fd 引用归零
专属图示:把 socket 的 fd、连接身份、字节流和回收责任放进同一条轨迹。

五个节点到机制证据

创建端点

产生一个尚未绑定或连接的 fd。记录进程、fd、地址族、类型和错误路径;创建失败时确认部分资源没有留在表中。

绑定监听

建立本地身份和 backlog 边界。监听 fd 不承载某个客户端的应用字节;地址占用、队列容量和重启策略都应有证据。

建立连接

产生新的连接状态。记录监听 fd、连接 fd、对端地址、握手结果、队列出入和所属线程;多个客户端不能共享一个模糊的“连接成功”标记。

收发字节

不保证一次调用完成一条消息。保存调用长度、实际处理长度、缓冲、应用帧和返回值,区分阻塞、暂时无数据与 EOF。

关闭连接

不是一个瞬间的布尔开关。记录 half-close、对端 EOF、错误、线程引用和释放顺序,避免 fd 泄漏或过早复用。

最小可重放实现

listener = socket()
bind(listener, address)
listen(listener, backlog=2)
connection = accept(listener)
write_all(connection, framed_message)
read_frame(connection)
close(connection)
close(listener)
assert reset() == empty_socket_table

这段草图只表达端点生命周期合同,不复制书中叙事或代码。实际复核应保存进程、fd、状态、五元组、队列、每次读写长度、EOF、关闭方向和最终 fd 表。

五步复核 socket 生命周期

分步1 / 5

1. 创建端点并固定 fd 所有者

记录进程、fd、地址族、类型和初始状态。先预测创建失败、重复关闭和资源回收时的 fd 表。

socket 生命周期:监听端点与连接端点分开验收fd、五元组、字节缓冲和关闭方向共同定义连接状态1创建端点fd + 类型状态证据2绑定监听地址 + 队列监听边界3建立连接五元组连接边界4收发字节缓冲 + 帧状态证据5关闭连接EOF + 回收状态证据close 本地成功不等于对端处理完成,也不等于所有 fd 引用归零
专属图示:把 socket 的 fd、连接身份、字节流和回收责任放进同一条轨迹。

Lab

fd、队列与关闭实验

只改变一个队列或回收条件,观察监听端点、连接 fd 和字节状态。

监听 fd 接收连接,accept 产生独立连接 fd

listen fd=3 → accept fd=4, tuple A → framed read/write → close fd=4

判定

通过:监听、连接和回收台账闭合

当前场景:基线连接;记录监听 fd、连接 fd、五元组、实际字节、EOF 和引用回收。

正常、边界与故障证据

socket 证据矩阵:fd 状态要和字节边界同时闭合正常看生命周期,边界看队列与短读,故障看首个返回值观察项正常边界故障端点fd 有主队列满创建拒绝连接五元组明排队accept 失败字节帧完整短读EOF回收引用归零半关闭fd 泄漏监听 fd、连接 fd、五元组、实际字节和关闭方向共同解释结果
专属图示:从端点创建到最后引用的四类 socket 验收证据。
样本只改变的变量预期判定必存证据
正常地址可用、队列有空间、消息完整关闭fd、五元组、字节与回收闭合fd 表、队列、五元组、读写和关闭记录
边界backlog、短读、缓冲容量或半关闭在对应边界等待或分段,不丢失所有权阈值、实际长度、EOF、剩余缓冲和引用
故障一次 accept、读写、关闭或回收动作失败首个状态拒绝可定位,修复后可重放首差、fd、返回值、所有者、复位结果

故障诊断:先找 fd 状态的首个矛盾

  1. 核对对象:确认当前 fd 是监听端点还是已连接端点,查看进程所有者、地址族、类型和状态。
  2. 核对身份:比较五元组、监听队列、connect/accept 事件和连接 fd,排除多个客户端被压成一条记录。
  3. 核对字节边界:按调用顺序排列请求长度、实际长度、缓冲、短读、EOF 和应用帧,找首个不满足协议的返回值。
  4. 核对回收闭合:检查 shutdown/close、等待者、未发送数据、引用计数和 fd 复用;修复后从空 fd 表重放。

术语表

名词解释

本章出现的专业名词,用大白话再讲一遍。

1.9 搞清楚Socket

由文件描述符承接地址、端口、协议状态和字节流的进程网络端点模型。

创建端点

为进程创建 socket 对象和文件描述符,并准备协议参数的阶段。

绑定监听

绑定本地地址和端口并进入接收连接请求状态的阶段。

建立连接

通过 connect 与 accept 产生带独立 fd 和五元组的已连接端点的阶段。

收发字节

通过已连接 socket 读写字节流并由应用协议恢复消息边界的阶段。

关闭连接

按关闭方向、EOF、等待者和最后引用结束生命周期并释放 fd 的阶段。

练习

练习

问题 1: 服务器调用 accept 后,监听 socket 是否变成了客户端连接 socket?

问题 2: 一次 write 发送 100 字节,接收端 read 只得到 40 字节,最应该怎样处理?

问题 3: 本地 close 成功但进程的 fd 表仍在增长,应该先查什么?

资料与写作方式声明

本章以码农翻身权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

本页小结

1.9 搞清楚Socket的关键不是记住一串调用名,而是能说明每个 fd 的状态、所有者、五元组、字节边界和关闭方向。完成标准是从创建端点重放到回收,在积压、短读或对端关闭中定位首个矛盾,并证明复位后监听、连接和 fd 台账重新闭合。

讨论

评论区加载中…