本文把Linux-2.6.11.12源码中文注释版中的注释收集出来,整理在下面。如有侵权,请告知。
TCP状态有如下11种:
enum {
TCP_ESTABLISHED = 1, //"Established"
TCP_SYN_SENT, //"Syn Sent"
TCP_SYN_RECV, //"Syn Recv"
TCP_FIN_WAIT1, //"Fin Wait 1"
TCP_FIN_WAIT2, //"Fin Wait 2"
TCP_TIME_WAIT, //"Time Wait"
TCP_CLOSE, //"Close"
TCP_CLOSE_WAIT, //"Close Wait"
TCP_LAST_ACK, //"Last ACK"
TCP_LISTEN, //"Listen"
TCP_CLOSING, //"Closing"
TCP_MAX_STATES /* Leave at the end! */
};
状态机函数有三个:
tcp_timewait_state_process(),tcp_rcv_synsent_state_process(),tcp_rcv_state_process(),主要工作如下:
tcp_timewait_state_process()
{
/* 用于处理在FIN_WAIT2和TIME_WAIT状态下接收到的段 */
/* 如果存在选项并且需要做序号回绕处理 */
/* 解析选项 */
/* 如果有时间戳,进行PAWS判断 tcp_parse_options*/
/* 如果timewait子状态是TCP_FIN_WAIT2 */
/* 如果PAWS检测未通过 或者 TCP序号不完全在接收窗口内,需要向对方发送ACK */
/* 如果接收到RST段,释放控制块并返回TCP_RW_SUCCESS */
goto kill:
/* 如果接收到SYN段,释放控制块并返回TCP_RW_RST */
goto kill_with_rst:
/* 如果在FIN_WAIT_2状态下,接收到非FIN段,或接收到的段序号与预期不符 kill*/
/* 接收到有效的FIN段,进入TIME_WAIT状态 */
/* 如果时间戳有效 */
/* 根据往返时间启动MSL定时器 */
/* 否则使用固定的60s作为MSL定时器 */
/* 返回TCP_TW_ACK,表示收到有效段,需要给对方发送ACK */
/* TIME_WAIT状态处理 */
/* 如果是预期段 */
/* 如果段没有被丢弃,则进入TIME_WAIT等待阶段 */
/* 启动FIN_WAIT_2或TIME_WAIT定时器 */
/* 如果在TIME_WAIT状态下接收到SYN段,且SYN段中没有RST和ACK标志,序号有效 */
/* 可接受该连接请求,重新计算初始序号后返回SYN由上层处理连接请求 */
/* 如果非RST段,只要没有回绕都需要向对方回送ACK */
}
tcp_rcv_synsent_state_process()
{
/* 在SYN_SENT状态下处理接收到的段,但是不处理带外数据 */
/* 解析TCP选项并保存到传输控制块中 */
/* 如果是ACK段,处理ACK标志 */
/* 如果收到ACK+RST段,需要tcp_reset设置错误码,并关闭套接口 */
/* 在SYN_SENT状态下接收到的段必须存在SYN标志,否则说明接收到的段无效,丢弃该段 */
/* 从首部标志中获取显示拥塞通知的特性 */
/* 如果支持ECN,则设置标志 */
/* 设置与窗口相关的成员变量 */
/* 根据是否支持时间戳选项来设置传输控制块的相关字段 */
/* 初始化PMTU、MSS等成员变量 */
/* 如果启用了连接保活,则启用连接保活定时器 */
/* 首部预测 */
/* 如果套口不处于SOCK_DEAD状态,则唤醒等待该套接口的进程 */
/* 连接建立完成,根据情况进入延时确认模式 */
/* 如果不需要延时确认,立即发送ACK段 */
/* 如果收到RST段,则丢弃传输控制块 */
/* PAWS检测失效,也丢弃传输控制块 */
/* 在SYN_SENT状态下收到了SYN段并且没有ACK,说明是两端同时打开 */
/* 设置状态为TCP_SYN_RECV */
/* 设置时间戳相关的字段 */
/* 初始化窗口相关的成员变量 */
/* 从首部标志中获取显式拥塞通知的特性。 */
/* 初始化MSS相关的成员变量 */
/* 向对端发送SYN+ACK段,并丢弃接收到的SYN段 */
}
tcp_rcv_state_process()
{
/* 除了ESTABLISHED和TIME_WAIT状态外,其他状态下的TCP段处理都由本函数实现 */
/*如果有ACK标志*/
switch(sk->sk_state) {
case TCP_SYN_RECV:
/* 正常的第三次握手,设置连接状态为TCP_ESTABLISHED */
/* 状态已经正常,唤醒那些等待的线程 */
/* 初始化传输控制块,如果存在时间戳选项,同时平滑RTT为0,则需计算重传超时时间 */
/* 建立路由,初始化拥塞控制模块 */
/* 更新最近一次发送数据包的时间 */
/* 计算有关TCP首部预测的标志 */
case TCP_FIN_WAIT1:
/* 处理FIN_WAIT1状态下接收到的ACK */
/* 通过ACK段的确认,所有发送段对方都已经收到,则迁移到FIN_WAIT2状态 */
/* 从对方收到ACK段,因此可以确认此路由缓存有效 */
/* 如果不在DEAD状态并且状态发生了变化,通过等待的线程 */
/* 否则在DEAD状态,则需要关闭传输控制块,或者在FIN_WAIT2状态等待 */
/* 无需要在FIN_WAIT2状态等待 或者 接收的段有数据并且接收的段都已经完毕 */
/* 无需等待,直接关闭套接口 */
/* 在FIN_WAIT2等待 */
case TCP_CLOSING:
/* 这个状态是处理同时关闭 */
/* 如果所有的段都已经收到 */
/* 迁移到wait状态 */
case TCP_LAST_ACK:
/* 如果所有段都已经收到 */
/* 更新路由缓存并关闭套接口 */
switch (sk->sk_state)
case TCP_CLOSE_WAIT:
case TCP_CLOSING:
case TCP_LAST_ACK:
/* 这三种状态,如果接收到已经确认过的段,则直接丢弃 */
case TCP_FIN_WAIT1:
case TCP_FIN_WAIT2:
/* 如果接收方向已经关闭 */
/* 如果接收到新数据 */
/* 给对方发送复位消息 */
case TCP_ESTABLISHED:
/* 对已经接收到的段进行排队,应该是在处理快速TCP,在发送ACK的同时发送了数据段 */
/* 如果tcp_data需要发送数据和ACK则在这里处理 */
/* 如果段没有加入队列,或者前面的流程需要释放报文,则释放它 */
}