-
Notifications
You must be signed in to change notification settings - Fork 32
/
4.5、TCP 流量控制与拥塞控制实现.md
283 lines (142 loc) · 13.6 KB
/
4.5、TCP 流量控制与拥塞控制实现.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# TCP 流量控制
* 为了让收发两方速率协调
## 实现方法
利用滑动窗口实现流量控制
* 一般说来,我们总是希望数据传输得更快一些。但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。
* 流量控制(flow control)就是让发送方的发送速率不要太快,既要让接收方来得及接收,也不要使网络发生拥塞。
* 利用滑动窗口机制可以很方便地在 TCP 连接上实现流量控制。
持续计时器
* TCP 为每一个连接设有一个持续计时器。
* 只要 TCP 连接的一方收到对方的零窗口通知,就启动持续计时器。
* 若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带 1 字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。
* 若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器。
* 若窗口不是零,则死锁的僵局就可以打破了。
## 小包问题
传输效率的思考
* 在有些协议通讯中,如Telnet,会有逐个字节的发送的情景,即每次发送一个字节的有用数据。
* 为了发送一个字节的数据会产生41个字节长的报文,其中有20个字节的IP首部和20个字节的TCP首部。
* 因此,信道利用率极低,只有1/40。小数据报文大量的出现会造成广域网上的拥塞。即设法增加发送的数据规模不但可以提高信道利用率,而且也有助于减少广域网的拥塞。
* 任何小于一个MSS 的任何数据报文都被视为小数据报文。
糊涂窗口综合症
* 症状
* 当接收端和发送端速率不匹配时,滑动窗口动态调整机制会产生一种称为“ 糊涂窗口综合症(Silly Window syndrome )” 的情况。
* 这个问题可以归结为小包的问题,就是由于发送端和接收端上的处理不一致,导致网络上产生很多的小包。在滑动窗口机制下,如果发送端和接收端速率差异很大,就会产生这种比较犯傻的状态:发送方发送的数据,有40 个字节的首部,而有效数据很少,甚至只有一个字节的有效数据。
* 解决办法
* 一种是“你糊涂我不糊涂”的方式,Nagle算法是比较典型的一种,也是目前TCP默认采用的方法。
* 一种是“治疗接收端糊涂”的方式,其中延迟ACK也是比较典型的一种方法。
Nagle 算法
* Nagle算法的基本思想:
* 尽可能避免发送小数据报文,一个TCP连接上最多只能有一个未被确认的小数据报文。
* **在小数据报文的确认报文到达之前不发送其他小数据报文。并且持续接受小数据报文,并在确认到来时以一个较大的报文发送出去。**
* Nagle 算法还规定,当到达的数据已达到发送窗口大小的一半或报文段最大长度时,就立即发送一个报文段!
* 在TCP 中,Nagle 算法可以被禁止
延迟ACK
* 延迟ACK 就是累积确认
* 如果对每个数据段都发送一个ack 确认,如果到达的是一个小数据报文则为此而发送的确认报文的代价比较高,所以tcp 会延迟一段时间。
* 如果这段时间内有数据发送到对端,则捎带发送ack ,如果在延迟ack 定时器触发时,则立即单独发送。
当Nagle 遇上延迟ACK
* 发送端产生了多个小数据报文需要向接收端发送,每个小数据报文的长度都小于MSS。
* 当第一个携带小数据报文的TCP段到达接收端后,对方因为延迟ack机制而没有及时发送ack。
* 发送端因为要发送的依然是小数据报文而启动Nagle算法,小数据报文不会立即发送,而是等待对接收端对第一次数据确认。
* 结果:网络延迟。
# TCP 拥塞控制
* 平衡网络负载
拥塞
* 即对资源的需求超过了可用的资源。若网络中许多资源同时供应不足,网络的性能就要明显变坏,整个网络的吞吐量随之负荷的增大而下降。
拥塞控制
* 防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
拥塞控制的前提:
* 网络能够承受现有的网络负荷。
* 拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素。
## 一般原理
拥塞发生的原因
* 在某段时间,若对网络中某资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏——产生拥塞(congestion)。
* 出现资源拥塞的条件:**对资源需求的总和 > 可用资源**
* 若网络中有许多资源同时产生拥塞,网络的性能就要明显变坏,整个网络的吞吐量将随输入负荷的增大而下降。
* 在许多情况下,甚至正是拥塞控制本身成为引起网络性能恶化甚至发生死锁的原因。这点应特别引起重视。
拥塞控制与流量控制的关系
* 拥塞控制是整个网络
* 拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。
* 拥塞控制是一个全局性的过程,涉及到所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。
* 流量控制是端对端的
* 流量控制往往指在给定的发送端和接收端之间的点对点通信量的控制。
* 流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收。
拥塞控制所起的作用
<img src="https://img-blog.csdnimg.cn/20210112202524337.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkzNDYwNw==,size_16,color_FFFFFF,t_70" alt="image-20210104201834073" width="40%"/>
开环控制和闭环控制
* 开环控制方法就是在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞。
* 闭环控制是基于反馈环路的概念。属于闭环控制的有以下几种措施:
* 监测网络系统以便检测到拥塞在何时、何处发生。
* 将拥塞发生的信息传送到可采取行动的地方。
* 调整网络系统的运行以解决出现的问题。
## 慢开始和拥塞避免
* 发送方维持一个叫做拥塞窗口 cwnd (congestion window)的**状态变量**。
* 拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。
* 发送方让自己的发送窗口等于拥塞窗口。如再考虑到接收方的接收能力,则发送窗口还可能小于拥塞窗口。
* 发送方控制拥塞窗口变量的原则是:
* 只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去。
* 但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。
慢开始算法
* 在主机刚刚开始发送报文段时可先设置拥塞窗口 cwnd = 1,即设置为一个最大报文段 MSS的数值。
* 在每收到一个对新的报文段的确认后,**将拥塞窗口加 1**,即增加一个 MSS 的数值。
* 用这样的方法逐步增大发送端的拥塞窗口 cwnd,可以使分组注入到网络的速率更加合理。
传输轮次
* “传输轮次”更加强调:把拥塞窗口 cwnd 所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。
* 假如拥塞窗口 cwnd = 4,这时的往返时间 RTT 就是发送方连续发送 4 个报文段,并收到这 4 个报文段的确认,总共经历的时间。
* 使用慢开始算法时,每经过一个传输轮次,拥塞窗口 cwnd 就会被加倍。
* 一个传输轮次所经历的时间其实就是往返时间 RTT。
* 发送方每收到一个对新报文段的确认(重传的不算在内)就使 cwnd 加 1。
<img src="https://img-blog.csdnimg.cn/20210112202548285.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkzNDYwNw==,size_16,color_FFFFFF,t_70" alt="image-20210104202731656" width="40%" />
门限状态变量及其设置方法:
* 门限状态变量(ssthresh)是指网络状态达到某个临界点,继续延续这种状态将导致状态发生转变。
* 当 cwnd < ssthresh 时,使用慢开始算法。
* 当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
* 当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法。
* 拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口cwnd 加 1,而不是加倍,使拥塞窗口 cwnd 按线性规律缓慢增长。
慢开始和拥塞避免算法具体过程:
* 慢开始阶段:
* 设 :ssthresh 为慢开始阈值,MSS 为最大 TCP 段长度,CongWindow 为拥塞窗口大小
* 初始 CongWindow 一般设置为 1 个 MSS , sstresh 设置为接收窗口大小
* **每收到一个确认 ACK** ,则 CongWindow= CongWindow + 1 个 MSS
* 当 CongWindow > sstresh 时,进入拥塞避免阶段。
* 拥塞避免阶段
* 在拥塞避免阶段,**每经过一个往返传输时间 RTT**(RTT 是动态变化的) ,则CongWindow=CongWindow+1 个MSS
* 不管是慢开始阶段,还是拥塞避免阶段,如果TCP**检测到拥塞(即出现超时)**,则**将sstresh 缩减成CongWindow 的一半,且CongWindow 恢复
为初始大小,即一个MSS** 。
慢开始和拥塞避免算法的实现举例
<img src="https://img-blog.csdnimg.cn/20210112202415926.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkzNDYwNw==,size_16,color_FFFFFF,t_7" alt="image-20210104204435314" width="60%" />
* 当 TCP 连接进行初始化时,将拥塞窗口置为 1(图中的窗口单位没使用字节而使用报文段)。
* 慢开始门限的初始值设置为 16 个报文段,即 ssthresh = 16。
* 发送端的发送窗口不能超过拥塞窗口 cwnd 和接收端窗口 rwnd 中的最小值。我们假定接收端窗口足够大,因此现在发送窗口的数值等于拥塞窗口的数值。
* 在执行慢开始算法时,拥塞窗口 cwnd 的初始值为 1,发送第一个报文段 M0 。
* 发送端每收到一个确认 ,就把 cwnd 加 1。于是发送端可以接着发送 M1 和 M2 两个报文段。
* 接收端共发回两个确认。发送端每收到一个对新报文段的确认,就把发送端的 cwnd加 1。现在 cwnd 从 2 增大到 4,并可接着发送后面的 4 个报文段。
* 发送端每收到一个对新报文段的确认,就把发送端的拥塞窗口加 1,因此拥塞窗口cwnd 随着传输轮次按指数规律增长。
* 当拥塞窗口 cwnd 增长到慢开始门限值 ssthresh 时(即当 cwnd = 16 时),就改为执行拥塞避免算法,拥塞窗口按线性规律增长。
* 假定拥塞窗口的数值增长到 24 时,网络出现超时,表明网络拥塞了。
* 更新后的 ssthresh 值变为 12(即发送窗口数值 24 的一半),拥塞窗口再重新设置为 1,并执行慢开始算法。
* 当 cwnd = 12 时改为执行拥塞避免算法,拥塞窗口按按线性规律增长,每经过一个往返时延就增加一个 MSS 的大小。
“乘法减小”和“加法增大”
* “乘法减小”
* 指不论在慢开始阶段还是拥塞避免阶段,只要出现一次超时(即出现一次网络拥塞),就把慢开始门限值 ssthresh 设置为当前的拥塞窗口值乘以 0.5。
* 当网络频繁出现拥塞时, ssthresh 值就下降得很快,以大大减少注入到网络中的分组数。
* “加法增大”
* 指执行拥塞避免算法后,在收到对所有报文段的确认后(即经过一个往返时间),就把拥塞窗口 cwnd增加一个 MSS 大小,使拥塞窗口缓慢增大,以防止网络过早出现拥塞。
必须指出:
* “拥塞避免”并非指完全能够避免了拥塞。利用以上的措施要完全避免网络拥塞还是不可能的。
* “拥塞避免”是说在拥塞避免阶段把拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。
## 快重传和快恢复
* 快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认。这样做可以让发送方及早知道有报文段没有到达接收方。
* 发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段。
* 不难看出,快重传并非取消重传计时器,而是在某些情况下可**更早地重传丢失的报文段**。
<img src="https://img-blog.csdnimg.cn/20210112202458914.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkzNDYwNw==,size_16,color_FFFFFF,t_70" alt="image-20210104205800725" width="50%" />
快恢复算法
* 当发送端收到连续三个重复的确认时,就执行“乘法减小”算法,把慢开始门限 ssthresh 减半。但接下去不执行慢开始算法。
* 由于发送方现在认为网络很可能没有发生拥塞,因此现在不执行慢开始算法,即拥塞窗口cwnd 现在不设置为 1,而是设置为慢开始门限 ssthresh 减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。
和慢开始+拥塞避免的区别
* 拥塞检测方法不同
* 拥塞避免根据出现超时来判断
* 快重传根据发送方收到三个重复确认报文来判断
* 拥塞后 cwnd 变量不同
* 拥塞避免变为 1个 MSS
* 快恢复变为 减半后的 ssthresh