> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/4.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/di-si-bu-fen-jin-cheng-jian-tong-xin/12.6.-tcp-shu-ru-chu-li.md).

# 12.6 TCP 输入处理

TCP 输入处理虽然远比 UDP 复杂，前几节已提供了考察其实际运作所需的背景。照例，输入例程带参数被调用：

```c
(void) tcp_input(m, ifp);
    struct mbuf *m;
    struct ifnet *ifp;
```

头几步开始耳熟了：

1. 在收到的 IP 数据报中定位 TCP 头。确认分组至少有 TCP 头那么长，必要时用 `m_pullup()` 使其连续。
2. 计算分组长度，设置 IP 伪头部，对 TCP 头和数据做校验和。校验和坏则丢弃分组。
3. 检查 TCP 头长度；大于最小头部时，确保整个头部连续，分配一个额外 mbuf，把 TCP 选项复制进去。
4. 按分组指定的端口号定位连接的协议控制块。不存在则发送含复位标志 RST 的分组并丢弃分组。
5. 检查套接字是否在监听连接；是则按被动连接建立的既定过程处理。
6. 处理分组头中的任何 TCP 选项。
7. 清除连接的空闲时间，把保活定时器设回正常值。

到这里，正常检查已做完，可以处理收到分组中的数据和控制标志了。正常处理期间仍须做许多一致性检查：例如还在建立连接时 SYN 标志必须在场、连接已建立后不得在场。讨论中略去多数检查，但这些测试对防止迷途分组引起混乱和可能的数据损坏很重要。

检查 TCP 分组的下一步是看分组按接收窗口是否可接受。这一步必须在检查控制标志（尤其 RST）之前做：旧的或无关的分组除非在当前语境中明确相关，不应影响现行连接。接收窗口非零、且分组占据的序号空间至少有一部分落在接收窗口内，报文段即合格。分组含数据时，部分数据必须落在窗口内；先于窗口的数据部分被裁掉（它们已被收到），超出窗口的部分也被丢弃（它们发得太早）。接收窗口关闭（`rcv_wnd` 为零）时，只有无数据且序号等于 `rcv_nxt` 的报文段合格。入局报文段不合格时，发出确认后丢弃。

4.3BSD Tahoe 发行版 TCP 应用这些测试的方式与原 4.3BSD 磁带发行版略有不同；这里采用 Tahoe 的测试，因为它们更正确（旧版本做类似的测试，只是顺序稍异）。处理步骤如下：

1. 检查分组是否始于 `rcv_nxt` 之前。是则无视分组中的任何 SYN，裁掉先于 `rcv_nxt` 的数据。无数据留下则发送当前确认并丢弃分组（分组推测为重复传输）。
2. 裁剪后分组仍含数据、而创建套接字的进程已关闭套接字时，发送复位（RST）并断开连接。这一复位对中止无法完成的连接必不可少；典型情形是远程登录客户在数据仍在接收时断开。
3. 报文段末端越过窗口时，裁掉窗口之外的数据。窗口关闭且分组序号为 `rcv_nxt` 时，分组按窗口探测处理：置 TF\_ACKNOW 发送当前确认和窗口更新，继续处理分组其余部分。SYN 置位且连接处于 TIME\_WAIT 状态时，这实际是个新的连接请求，旧连接被丢弃——这一过程被称为快速连接重用（rapid connection reuse）。否则，无数据留下则发送确认并丢弃分组。

TCP 输入处理的其余步骤检查下列标志和字段并采取相应动作：RST、ACK、窗口、URG、数据、FIN。分组既已确认合格，这些动作可以直截了当地做：

4. RST 置位则关闭连接并丢弃分组。
5. ACK 未置位则丢弃分组。
6. 确认字段值高于此前的确认时，有新数据被确认。连接处于 SYN\_RECEIVED 态且分组确认我们的 SYN 时，进入 ESTABLISHED 态。新确认的序号范围包括正在测往返时间的那个序号时，把时间样本平均进连接的平滑往返时间估计。全部未决数据确认完毕则停止重传定时器；否则重设为当前超时值。最后从套接字发送队列删除已确认的数据。FIN 已发出且被确认则推进状态机。
7. 检查窗口字段看是否推进了已知的发送窗口。先查这是不是新的窗口更新：分组序号大于前次窗口更新的序号，或序号相同而确认更高，或序号确认都相同而窗口更大，则记录新窗口。
8. 紧急数据标志 URG 置位时，把分组中的紧急指针与上次收到的比较。不同则有新的紧急数据发出：紧急指针用来计算 `so_oobmark`——从套接字接收缓冲开头到紧急标记的偏移（10.6 节），并经 `sohasoutofband()` 通知套接字。紧急指针小于分组长度时，紧急数据已全部收到。TCP 通常把紧急模式发送的那个数据八位组（紧急指针前的最后一个八位组 ）取出存进协议控制块，等 PRU\_RCVOOB 请求时取用；套接字选项可以要求把紧急数据留在正常数据里。
9. 终于检查收到分组的数据字段。数据始于 `rcv_nxt` 则可用 `sbappend()` 直接放进套接字接收缓冲；否则分组保留在每连接队列里，等中间数据到来。协议控制块置 TF\_DELACK 标志，表示需要确认但不立即发送，希望它能搭在很快要发的分组（大概是为响应入局数据而发）上，或与很快要收到的其他数据的确认合并。下次 `tcp_fasttimo()` 例程运行时，会把标志改为 TF\_ACKNOW 并调用 `tcp_output()` 例程发送确认。
10. 处理收到分组的最后一步检查 FIN 标志。它在场时连接状态机可能要推进，套接字经 `socantrcvmore()` 标记以传达文件结束指示。发送侧已关闭（FIN 已发且确认）时，套接字就此视为关闭，经 `soisdisconnected()` 标记。置 TF\_ACKNOW 标志强制立即确认。

第 10 步完成了 `tcp_input()` 收到新分组时的动作。但如前所述，收到输入可能需要新的输出：尤其全部未决数据的确认或新的窗口更新，需要输出模块新的输出或状态变化；若干特殊条件也置 TF\_ACKNOW 标志。这些情况下，输入处理结束时调用 `tcp_output()`。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://book.bsdcn.org/4.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/di-si-bu-fen-jin-cheng-jian-tong-xin/12.6.-tcp-shu-ru-chu-li.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
