没做的与小结
这章没做的(很多,诚实列)
这一章砍掉的是 TCP 的「鲁棒性」那一半,需要 timer 基建,CinuxOS 这会儿没有:
- 重传 / RTO / 滑动窗口 / 拥塞控制:这一章不丢包就工作,丢包没重传(对端不 ACK 就卡)。真 TCP 的可靠性全在这,要内核 timer-wake 基建。
- TIME_WAIT:主动关方 ACK FIN 后直接 Closed,不等 2MSD(要 timer)。
- ISN 随机化:用确定性递增计数器(测试可复现),随机化(防序号预测)留 follow-up,跟 ASLR 那套安全考虑同族。
- 乱序重组 / 重复 ACK / 快速重传:乱序包直接丢,不缓存不重组。
- TCP Socket API:
listen/accept/recv/sendto没有——这一章是协议层,socket 层是下一章。 - production net_init 接线:这一章 test-only(没消费者),真接进 net_init 等有 socket 消费者。
对照 Linux:完整 TCP 的可靠性那一半
上面这份「没做」清单,正好是 Linux TCP 跟咱们这版拉开差距的地方——Linux 的 TCP 是 production-grade 的可靠性实现,核心是三套咱们没碰的机制。
滑动窗口(流控):TCP 头里那个 16 位的 window 字段,本意是接收方通告「我还能收多少字节」(rwnd),发送方据此限速,别发得比对端缓冲能接的还快。Cinux 的 window 写死成 kTcpWindow = 8192(tcp.cpp:29),每段都填这个常量,既不反映真实可用缓冲、也不随收发动态调整——等于这个字段是占位,没做流控。
拥塞控制:这是 TCP 的精髓——发送方主动探测网络承载力,别把链路压崩。它的标准四件套是慢启动(拥塞窗口 cwnd 指数增长到一个阈值)、拥塞避免(过阈值后线性爬)、快重传(收到几个重复 ACK 就不等超时、立刻重发那个丢的段)、快恢复(把阈值砍半,不退回慢启动)。Cinux 这一侧,cwnd / 阈值 / 重复 ACK 计数全没有——前面那个写死的 window 是唯一的「窗口」概念,而且它是流控的、不是拥塞的。
重传:可靠性最后落在「丢了就重发」。Linux 给每个连接维护重传队列(发出去未 ACK 的段都留着),靠估计往返时间算超时,超时就重传,配合重复 ACK 的快重传。Cinux 发出去的段不缓存、不算往返时间、没 timer——对端不 ACK 就永远卡着,这一章「在一切顺利的前提下对」指的就是这个:不丢包则全对,一丢包就停。
合起来,Linux TCP 是「会自适应、会重传、抗丢包抗拥塞」的可靠字节流;Cinux 这版是「握手 / 数据 / 挥手的协议状态机骨架,假设链路不丢不乱序」。砍掉的不是细枝末节,是 TCP 鲁棒性的整套地基——而那套地基的头一个前提是内核 timer 基建(CinuxOS 这会儿没有),这正是边界画在这里的原因。
小结
- TCP(协议号 6)挂进 063 立的 L4 表(
ipv4.add_l4(kIpProtoTcp, tcp)),加协议不疼。 - TCP 比 UDP 多一台连接状态机:每个连接一个 TCB(state / 4-tuple / iss / snd_nxt / rcv_nxt),固定 8 槽,在握手→established→挥手间转换。状态机是 TCP 灵魂,也是篇幅所在。
- 核心算术:SYN 占 1 序号、FIN 占 1 序号、数据占 len;
snd_nxt是下个发的,rcv_nxt是下个期望收的(=ACK 值)。三次握手协商序号,数据按序 + ACK 推进 rcv_nxt,四次挥手靠 FIN(占 1 序号)+ ACK 拆连接。 - 校验和必填(不像 UDP 可省),伪首部 proto=6 + 段,连续缓冲区一把算(同 UDP trick)。
- 底子优先:host 单测(NoL2Dev 捕获再 deliver,逐包断言 seq/ack)→ loopback 内核(poll budget loop 排干,4 polls 跑完握手+数据+挥手)→ e1000 TX。避重入(用 poll 拍扁,不在回调里发包)。
- 诚实边界:这是最小可用 TCP——重传/RTO/窗口/拥塞/TIME_WAIT/ISN 随机化/乱序重组都没做(要 timer 基建);socket API 留下一章。