[笔记] tcp/ip
第12章 TCP:传输控制协议
处理通信错误可以通过 差错校正码 和 “尝试重新发送”(ARQ) 两种方案。TCP采用的是ARQ。
12.1.1 ARQ和重传
我们如何判断接收方正确地接收到分组?
- 接收方是否已经收到分组 => 接收方通过ACK告诉发送方
- 分组是否正确 => CRC等校验
上诉方案带来的问题
- ACK也是一个分组,发送方需要等待多久才会重发分组呢?
- 如果ACK丢失了该怎么办?
- 如果收到的分组出现差错怎么办?
ACK丢失,发送方无法判断是原分组丢失还是ACK丢失,只能重发。 => 要求接收方拥有去重的能力 => 序列号解决 => 要求发送方为每一个新的分组生成唯一序列号并附带在packet上
分组差错 => 校验码,只判断正确性,不拥有纠错能力
上诉方案问题:
发送方发送后只能等待ACK,吞吐量不高 => 经典的停止等待协议
=> 引入多个分组(流水线处理)
=> 产生了新问题
对于发送方来说:
=> 何时注入分组
=> 注入多少个分组
=> 等待ACK时如何重置定时器
=> 直到接收方未正确接受分组前, 副本要一直保存 => 重传需求
对于接收方来说
=> 更复杂的分组保存机制,因为分组到达顺序和序号不一定是一致的
=> 接收方接受速率和发送方发送速率不匹配怎么办?
12.1.2 分组窗口和滑动窗口
12.1.3 滑动窗口通过接收方的ACK可以实现流量控制和拥塞控制
12.1.4 如何处理重传超时
RTT
12.2 TCP
12.2.1 TCP模型
TCP是流模型,没有显示的记录标志或消息边界。
12.2.2 TCP的可靠性
- TCP发送一个窗口的数据只会设置一个定时器,当ACK到达时再更新超时。
- TCP接收方接收到数据时,可能会延迟片刻发送ACK,ACK中的序列号之前的字节已经被接收(累积确认)。优势在于只要最后一个ACK未丢失,那么即可确认之前的报文。
- TCP是双工服务,因此发送方和接收方分别维护自己的序列号。
- 序列号可以处理无需到达的packet,它们会被重组成有序的流并提供给上层应用
12.3 TCP头部和封装
- TCP头至少20bytes,带选项最多可扩展至60bytes
- TCP约等于"一种带累积正向确认的滑动窗口协议"
- ACK = 接收方已经顺序接收到的最大字节(加1) => 选择确认选项
- TCP窗口是16bit,限制了窗口最大时65535字节 => 窗口缩放(Window Scale)可以增加窗口大小
第13章 TCP连接管理
13.2.3 初始序列号
使用相对随机的初始序列号。
13.2 TCP连接的建立和终止
server可调用shutdown等待客户端发送fin
13.2.5 连接超时
client向server发送syn请求,如果server不响应,那么client则会重复发送(ARQ),发送则有时间间隔和次数限制(net.ipv4.tcp_syn_retries),默认重试5次。
13.2.6 tcp连接和NAT
13.3 TCP选项
SACK => 选择确认
TSOPT => 时间戳选项
TCP最大段大小数值最大值为1460 = MTU(1500字节) - IPV4头部(20字节) - TCP头部(20字节)
ipv6 1440 => MTU - IPV6头(40字节) - TCP头部(20字节)
13.3.2 选择确认
13.3.4 时间戳选项和防止回绕序列号
时间戳单调递增,旧packet因为时间戳小于当前时间戳,会被丢弃,有效阻止回绕序列号。
13.4 TCP MTU发现
13.5 TCP状态转换
13.5.2 TIME_WAIT状态
终止服务器然后短时间内又再次打开,此时会报"地址已被占用"的错误(2MSL的等待状态造成的)。
2MSL状态。server被动关闭时,如果收不到client发过来的ACK会不断重传FIN,直到它收到一个最终的ACK。使用选项SO_REUSEADDR,当一个连接处于2MSL等待状态时,任何延迟到达的报文都会被丢弃。
13.5.4 FIN_WAIT_2状态
防止FIN_WAIT_2无限等待 => 如果主动关闭应用程序执行的是完全关闭操作,系统会设置一个定时器。
net.ipv4.tcp_fin_timeout
13.6 重置报文段
RST报文
13.6.1 不存在端口的连接请求
请求到达本地却没有应用监听该端口,则产生rst报文 => 可用于查询某服务是否活着
13.6.2 终止一条连接
默认FIN是有序释放 => FIN要在所有排队数据已经发送后才被发送出去
=> SO_LINGER=0
终止连接的特性:
1. 任何排队数据都将被抛弃,RST报文立刻发出
2. RST报文的接收方会说明通信的另一端采用了终止的方式而不是正常关闭
13.6.3 半开连接
client突然断电,server半连接 => client原来相同ip:port发往服务器则收到RST
或服务器主动发FIN,如果client突然关闭,也收到RST(因为没有应用监听该端口了)
13.6.4 时间等待错误
2MSL状态收到RST报文或更加特殊的重置报文段。
当client处于2MSL状态收到旧报文,并回复报文时,server没有关于这条连接的任何信息,会发送RST导致client过早转移到CLOSED状态。
许多系统规定处于TIME_WAIT状态时忽略RST报文,规避上诉问题。
13.7 TCP服务器选项
netstat -a -n -t # -t tcp -n 十进制ip
13.7.4 进入连接队列
SYN_RECV状态连接个数限制 => net.ipv4.tcp_max_syn_backlog => 超过阈值的连接会被拒绝
三次握手完成,但并被accept => net.core.somaxconn
13.8 与TCP连接管理相关的攻击
14 TCP超时与重传
14.1 引言
TCP通过
(1) 时间
(2) ACK信息
实现可靠数据传输服务。
发送数据 => 计时器 => 超时回调(重传超时RTO)
=> 累积确认无法返回新ACK或ACK的SACK失序 => 快速重传
通常来说,当发送端认为接收端可能出现数据丢失时,决定发送新数据or重传。
14.2 简单的超时与重传举例
- 足够大的时间间隔(5秒)重传一次
- tcp与不存在的主机建立连接时,tcp尝试重新建立连接时会采用比上次更长的时间间隔
- 以太网冲突
重传间隔时间加倍(二进制指数退避(binary exponential backoff))
重传的判断指标:
1. 重传次数上限
2. 每次重传的间隔
#net.ipv4.tcp_retries1
#net.ipv4.tcp_retries2
#net.ipv4.tcp_syn_retries
#net.ipv4.tcp_synack_retries
cat /proc/sys/net/ipv4/tcp_retries1
cat /proc/sys/net/ipv4/tcp_retries2
tcp_retries1 (integer; default: 3; since Linux 2.2)
The number of times TCP will attempt to retransmit a packet on an established
connection normally, without the extra effort of getting the network layers
involved. Once we exceed this number of retransmits, we first have the network
layer update the route if possible before each new retransmit. The default is the
RFC specified minimum of 3.
tcp_retries2 (integer; default: 15; since Linux 2.2)
The maximum number of times a TCP packet is retransmitted in established state
before giving up. The default value is 15, which corresponds to a duration of
approximately between 13 to 30 minutes, depending on the retransmission timeout.
The RFC 1122 specified minimum limit of 100 seconds is typically deemed too short.\
tcp_syn_retries (integer; default: 6; since Linux 2.2)
The maximum number of times initial SYNs for an active TCP connection attempt will
be retransmitted. This value should not be higher than 255. The default value is
6, which corresponds to retrying for up to approximately 127 seconds. Before Linux
3.7, the default value was 5, which (in conjunction with calculation based on other
kernel parameters) corresponded to approximately 180 seconds.
tcp_synack_retries (integer; default: 5; since Linux 2.2)
The maximum number of times a SYN/ACK segment for a passive TCP connection will be
retransmitted. This number should not be higher than 255.
14.3.2 如何计算RTT
14.3.2.4 带时间戳选项的RTT测量
14.4 基于计时器的重传
TCP发送段每发送一个新的数据包时,需设定一个新的计时器,并记录新的序列号。如果数据没有丢失,则会不断地设定和取消一个重传计时器。
14.5 快速重传
快速重传是基于接收端的反馈信息来引发重发,而非计数器超时。因为计数器超时的间隔相对来说比较长,快速重传能够更加及时有效地修复丢包情况。
当接收端收到失序报文段时,立刻生成确认信息(重复ACK),并且失序情况表明在后续数据到达前出现了丢段,即接收端缓存出现了空缺。发送端根据该信息尽快填补空缺。
失序报文触发条件:
1. 网络延迟,后发先至
2. 丢包
=> 重复ACK => 决定是否触发快速重传
14.6带选择确认的重传
ACK + SACK来向发送端发送失序的数据
小于等于ACK的序号一定是连续的,大于ACK则成为失序数据。
SACK的优势:在一个RTT内能够获知多个空缺。
14.6.1 SACK接收端行为
接收端何时生成ACK
=> 丢包
=> 旧数据先到达
14.6.2 SACK发送端行为
收到SACK可以发送新数据或重传旧数据。
14.7 伪超时与重传
14.8 包失序与包重复
14.8.1 失序
网络环境中无法保证IP包有序。可能原因
=> ip层可以换一条其他链路发送数据
=> 存在硬件并行的路由器
失序发生在ACK链路时
=> 窗口快速前移,然后又接受到重复且应被丢弃的ACK
失序发生在正向链路
=> 接收端可能无法正确判断失序和丢包
14.8.2 重复
14.11 与TCP重传相关的攻击
低速率DoS攻击 => 随机RTO
第15章 TCP数据流与窗口管理
15.2 交互式通信
15.3 延时确认
许多情况下TCP并不对每个到来的数据包都返回ACK,利用TCP的累积ACK字段即可实现该功能。其实就是将ACK附带在同方向的需要发送的数据包上进行传输。TCP不能任意时间延迟ACK,否则对方误认为出现数据丢失而进行不必要的重传。
15.4 Nagle算法
核心思想是将小的报文段合并成一个报文段然后发送。
15.4.1 延时ACK与Nagle算法
可能产生死锁
15.4.2 禁用Nagle算法
要求延时小的应用应该禁用。
15.5 流量控制与窗口管理
15.5.1 滑动窗口
15.5.2 零窗口与TCP持续计时器
15.5.3 糊涂窗口综合征
15.6 紧急机制
15.7 与窗口管理相关的攻击
第16章 TCP拥塞控制
16.1 引言
TCP流量控制基于ACK数据包中的通告窗口大小字段来实现的。
16.1.1 TCP拥塞检测
如果网络拥塞,那么重传则会导致重传更多的数据包 => 所以需要解决这个问题
如何判断是否出现了拥塞 => 判断是否出现了丢包
有线网络 => 路由器、交换机拥塞 => 丢包
无线防落 => 传输和接收错误 => 丢包
当出现丢包时,tcp需要做的工作:
=> 重传数据包
=> 判断是否出现拥塞,如果是则执行减速操作
16.1.2 减缓TCP发送
实际发送窗口 = min(拥塞窗口,接收端通知窗口)
16.2 一些经典算法
16.2.1 慢启动
16.2.2 拥塞避免
第17章 TCP保活机制
一些情况下,虽然应用进程之间没有任何的数据交换,但是仍然需要通过连接保持一个最小的数据流 => TCP保活机制
reference
- 摘抄自《TCPIP详解》
- ubuntu TCP protocol