![](https://csdnimg.cn/release/download_crawler_static/14094117/bg5.jpg)
//因为处在 listen 状态的 pcb 都是在等待对端的连接,不需要超时处理。
}
3.2.1 active 状态 pcb 的超时处理
初始化 pcb 是否需要移除的变量 pcb_remove
如果当前 pcb 的状态是已发送 syn(SYN_SENT),并且重传次数达到了 syn 最大的重传
次数(TCP_SYNMAXRTX),则增加 pcb_remove 变量
否则,如果重传次数达到了 tcp 最大重传次数(TCP_MAXRTX),就增加 pcb_remove
变量。此时应该是某个 ack 的最大重传次数
如果上述两个条件都不满足:
该 pcb 的重传定时器增加 500 个滴答。
如果该 pcb 的未确认段队列不为空,也就是说存在未确认的段,并且上述重传定时器计
数值大于设定的重传超时时间,说明某个段很可能丢失了,超时重传将发生{
//此时,除非我们处于尝试连接某个对端,否则,将超时重传时间加倍。因为处于
连接建立阶段的超时时间是固定的,典型值是 75 秒。
如果当前不是在 SYN_SENT 状态,重新计算超时重传时间。(重传定时器的重传
时间的取值是依赖与连接上测算到的 RTT 的)
当超时发生时,表明发生了拥塞,tcp 要执行慢启动和拥塞避免算法。(算法细节
1234 步骤卷一 235 页)。首先取拥塞窗口(cwnd)和接收者通告的窗口(snd_wnd)中的小
值作为当前的窗口,将当前的阀值(ssthresh)减小到当前窗口的一半,如果阀值小于路径
最大段,则设置为 2 个报文段的大小。(因为阀值是按照段的大小增加的,所以如果不小于
一个的话就至少是两个)最后设置当前的拥塞窗口为一个段的大小。
调用 tcp_rexmit_rto()重传未确认队列上的第一个段。
}
//检查是否有 pcb 在 fin-wait-2 状态停留了太长时间。
如果当前 pcb 是在上述状态,并且 tcp 定时器当前的滴答数 tcp_ticks 与该 pcb 中保存的
变量 tmr(该变量主要用于保存连接最后一次活跃时的时间)的差值大于设定的该状态的超
时时间,则 pcb_remove 变量加一(该变量在后续移除不用的 pcb 时用到)。
//检查是否需要发送保活探测报文(KEEPALIVE)。
如果当前的连接支持保活探测选项(SO_KEEPALIVE),并且当前的连接处于建立
(ESTABLISHED)或者 CLOSE-WAIT 状态{
如果当前时钟滴答数 tcp_ticks 和 pcb 中 tmr 变量的差值大于保活探测前空闲的时间
和保活探测报文发送消耗的最长时间之和,那么说明该连接空闲了太长时间,该连接不再需
要。调用 tcp_abort 向对端发送一个 RST 报文,并释放与该连接相关的存储。
否则,如果该时间在保活探测报文发送期间,还没有达到保活探测报文发送的最
大次数,那么就调用 tcp_keepalive 继续发送保活探测报文,增加该 pcb 上的保活探测报文发
送计数变量 keep_cnt。
}
//如果该连接上保存有序号外的数据,并且有很长时间不再活跃了,则将序号外的数据
丢弃(这些数据如果最终需要传输的话还是会通过重传来完成的)
如果该连接的序号外段数据队列不为空,并且当前时钟滴答数和 tmr 的差值大于等于设