首页 > 代码库 > 《TCP/IP详解卷2:实现》笔记--TCP的输入
《TCP/IP详解卷2:实现》笔记--TCP的输入
当收到的数据报的协议字段指明这是一个TCP报文段时,ipintr(通过协议协议转换表中的pr_input函数)会调用tcp_input
进行处理,tcp_inut在软件中断一级执行。
函数非常长,我们将分两张讨论,下图列出了tcp_input中的处理框架。本章将结束对RST报文段处理的讲解,下一章开始
介绍ACK报文段的处理。
头几个步骤是非常典型的:对输入报文段做有效性验证(检验和、长度等),以及寻找连接的PCB。尽管后面还有大量的
代码,但通过“首部预测”,算法却有可能完全跳过后续的逻辑。首部预测算法是基于这样的假定,一般情况下,报文段既
不会丢失,次序也不会错误,因此,对于给定连接,TCP总能猜到下一个接收报文段的内容。如果算法起作用,函数直接
返回,这是tcp_input中最快的一条执行路径。
1.预处理
该部分介绍对收到的TCP报文段进行于预处理。处理的大概流程如下:
1.从第一个mbuf中获取IP和TCP首部。
2.验证TCP的检验和。
3.验证TCP偏移字段。
4.把IP和TCP首部及选项放入第一个mbuf。
5.快速处理时间戳选项。
6.保存输入标志,把字段转换成主机字节序。
7.寻找Internet PCB。
8.如果没有找到PCB,则丢弃报文,并发送RST作为响应。
9.如果TCP控制块存在,但连接状态为closed,说明插口已创建,且得到了本地地址和本地端口号,但还未调用connect或
listen。报文段被丢弃,且不发送任何响应。
10.不改变通告窗口大小。
11.如果选定了插口调试选项,则保存连接状态及IP和TCP首部。
12.如果监听插口收到了报文段,则创建新的插口。
13.计算窗口缩放因子。
14.复位空闲时间和保活定时器。
15.如果不处于监听状态,处理TCP选项。
2.首部预测
首部预测算法通过处理两种常见现象,简化单向数据传输的实现。
1.如果TCP发送数据,连接上等待接收的下一个报文段是对已发送数据的ACK。
2.如果TCP接收数据,连接上等待的下一个报文段时顺序到达的数据报文段。
3.TCP输入:缓慢的执行路径
下面介绍首部预测失败时的处理代码,tcp_input中较慢的一条执行路径。
1.丢弃IP和TCP首部,包括TCP选项。
2.计算接收窗口。
因为函数后面的代码必须确定通告窗口中能放入多少数据,所以现在必须计算通告窗口的大小。落在通告窗口之外的接收
数据被丢弃;落在窗口左侧的数据是已接收并确认过的数据,落在窗口右侧的数据时暂时不允许对端发送的数据。
4.完成被动打开或主动打开
如果连接状态等于LISTEN或者SYN_SENT,则执行本节的处理。连接处于这两个状态时,等待接收的报文段为SYN,任何
其他报文将被丢弃。
4.1.完成被动打开
4.2.完成主动打开
5.PAWS:防止序号回绕
6.裁剪报文段使数据在窗口内
7.自连接和同时打开
8.记录时间戳
下面给出了tcp_input的处理收到的时间戳选项。
如果收到的报文段中带有时间戳,时间戳值保存在变量中。
9.RST处理
下面给出处理RST标志的switch语句,取决于当前的连接状态。
1.SYN_RCVD状态下,插口差错代码设定为ECONNREFUSED,关闭插口。
2.如果在ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2或CLOSE_WAIT状态收到RST,则返回差错代码ECOORESET。
3.如果状态为CLOSING、LAST_ACK或TIME_WAIT,由于应用进程已关闭插口,无需返回差错代码。
4.如果SYN标志依旧置位,说明出现了差错,连接被丢弃,返回代码ECONNRESET。
5.如果ACK标志未置位,报文被丢弃。
《TCP/IP详解卷2:实现》笔记--TCP的输入