文档章节

TCP协议详解-滑动窗口

无毁的湖光-Al
 无毁的湖光-Al
发布于 2017/02/08 12:00
字数 2044
阅读 1.2K
收藏 9

  TCP协议作为基本的传输控制协议,提供了面向连接的、可靠的通信机制。由于其优越的特性,被广泛应用于网络通信中,成为了今天互联网的基石。其为了屏蔽网络底层种种复杂的因素做出了巨大的努力,同时也导致了TCP内部各种机制之间的相互作用,让初接触它的人们很难理清头绪。本文就从TCP的传输窗口这个点切入,带领大家一睹TCP实现机制的风采。

1. 前言

        我们大部分业务都建立在TCP之上,而且都经过框架层层的封装,让人很难看清其中的奥妙。但在和外部机构(如银行)交互的过程中,有很多采用的是自研的基于TCP的协议。此时无法依赖框架,我们就只能自己去编写基于TCP的代码,如果充分了解TCP的种种特性,和他们对接起来就会事半功倍。相信大家在开发TCP代码的过程中,也肯定了解了粘包、长短连接这些概念。粘包和TCP窗口有关、长短连接性能优劣和TCP传输策略有关。下面就着重介绍TCP窗口、TCP传输策略和TCP定时器,让大家对TCP有进一步的了解。

2. TCP窗口

        TCP发送窗口由slide_window(滑动窗口)、congestion_window(拥塞窗口)两者决定,代码如下(4.4BSD-Lite2):

1

2

3

4

5

6

7

#已发送未确认的字节数=下一个发送序号-最早的未确认序号

off = tp->snd_nxt - tp->snd_una;

#发送窗口为min(当前发送窗口,拥塞窗口)

win = min(tp->snd_wnd, tp->snd_cwnd);

...

#发送长度=发送窗口-已发送未确认字节数

len = min(so->so_snd.sb_cc, win) - off;

2.1 滑动窗口

        上面的snd_wnd、snd_una、snd_nxt三个字段组成了滑动窗口。 如下图所示:

2.2 发送端滑动窗口

        发送端窗口随时间滑动图(不考虑重传)例如下所示:

        (1)我们一共需要发送900字节数据。可发送数据为1-500字节,尚未发送数据。假设首先发送400字节的数据。
        (2)发送了400字节后,对端返回一个ack表示收到200序号之内的数据且窗口通告为500。于是如图示,窗口向前滑动了200字节。当前已发送未确认字节序号为200-400,可发送字节序号为401-700,假设在此尚未发送数据。
        (3)对端返回一个ack表示收到400序号内的数据且窗口通告为400。于是如图示,窗口向前滑动了200字节。已确认数据序号为1-400,可发送数据为401-800。

2.3 接收端窗口通告

        snd_wnd此字段主要由接收端的窗口通告决定,接收端窗口通告由当前接收端剩余多少空闲的剩余缓存决定。如下图所示:

        (1)发送端:写入2KB的数据[seq=0]。
        (2)接收端:收到数据,初始化接收端缓冲区4K,写入后还剩2K,于是通告ack[seq=2048,win=2048]。
        (3)发送端:接收到窗口通告为2048,于是最多只能写入2K的数据,将2K数据写入[seq=2048]。
        (4)接收端:应用层尚未消费缓冲区。接收到2K数据后,缓冲区满。于是通告窗口为0,返回ack[seq=4096,win=0]。
        (5)发送端:由于发送窗口为0,不能发送任何数据。此时发送端就需要定时的发送1字节的数据去探测接收端窗口。所需的定时器即为持续定时器(TCPT_PERSIST)。
        (6)发送端:发送0字节的探测数据。
        (7)接收端:缓冲区满,窗口通告为0,ack[seq=4096,win=0]。
        (8)发送端:继续发送0字节的探测数据。
        (9)接收端:缓冲区被应用层消费了2K,缓冲区可用字节为2K,通告窗口为2048,ack[seq=4096,win=2048]。
        (10)发送端:继续写入1K的数据。

2.4 拥塞窗口

        TCP用拥塞窗口(cwnd)来进行拥塞控制,主要利用了慢启动、拥塞避免、快速重传和快速恢复这四个算法。

2.4.1 慢启动和拥塞避免

        拥塞避免算法和慢启动算法是两个目的不同、独立的算法。慢启动的目的是:防止一开始速率过快,导致耗尽中间路由器存储空间,从而严重降低TCP连接的吞吐量。拥塞避免的目的是:当拥塞发生时,降低网络的传输速率。这可以通过调用慢启动的动作来降低网络的传输速率。所以在实际中这两个算法通常在一起实现。
        下述代码描述的是慢启动的过程(4.4BSD-Lite2)。 

1

2

3

4

5

6

7

8

{

u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;

 if (win < 2)

win = 2;

tp->snd_cwnd = tp->t_maxseg;

tp->snd_ssthresh = win * tp->t_maxseg;

tp->t_dupacks = 0;

}

        其将win置为现有窗口的大小,同时慢启动门限tp->snd_ssthresh设置为现有窗口大小的一半。snd_cwnd(拥塞窗口)被设定为只能容纳一个报文t_maxseg),这样就强迫TCP执行慢启动。之后拥塞窗口会先以指数形式增长,达到慢启动门限snd_ssthressh之后,再线性增长。
        线性增长的过程即是拥塞避免算法。
        此过程如以下代码注释所示(4.4BSD-Lite2):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

/*

* When new data is acked, open the congestion window.

* If the window gives us less than ssthresh packets

* in flight, open exponentially (maxseg per packet).

* Otherwise open linearly: maxseg per window

* (maxseg * (maxseg / cwnd) per packet).

*/

{

 register u_int cw = tp->snd_cwnd;

 register u_int incr = tp->t_maxseg;

 if (cw > tp->snd_ssthresh)

  incr = incr * incr / cw;

  tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);

}

        慢启动图例:

        图中Cwnd指数增长的阶段,即从1到ssthresh时间段是过程是慢启动。
        图中Cwnd线性增长的阶段,即从ssthresh到max的时间段是拥塞避免的过程。
        值得注意的是,TCP连接刚建立时刻也会有慢启动的过程。如果用的是短连接(即发送一个请求之后即抛弃此连接)且发送数据较少的话,大部分时间都耗在了慢启动上面,并没有充分的利用带宽。再加上建立连接所需要三次握手的消耗,导致短连接的效率要远低于长连接。

2.4.2 快速重传和快速恢复

        快速重传和快速恢复算法各自独立,但一般都在一起实现。

  • 快速重传:在接收到相同ACK后,推断出丢失报文段起始序号,然后立即重传此报文
  • 快速恢复:在快速重传的基础上,如果发生了快速重传,则执行拥塞避免算法而非慢启动。

        快速重传和快速恢复图例:

        从上图中我们可以看到,快速恢复的时候tcp窗口仅仅降低到ssthresh而后线性增加,即只进行了拥塞避免算法。

2.5 TCP粘包

        经过上述讨论,可知TCP窗口的大小取决于当前的网络状况、对端的缓冲大小等等因素,TCP将这些都从底层屏蔽。开发者无法从应用层获取这些信息。这就意味着,当你在接收TCP数据流的时候无法知道当前接收了有多少数据流,数据可能在任意一个比特位(seq)上。这就是所谓的"粘包"问题。开发者必须小心的组织帧格式来解决"粘包"。关注笔者公众号,获取更多干货文章。

© 著作权归作者所有

无毁的湖光-Al

无毁的湖光-Al

粉丝 496
博文 35
码字总数 65973
作品 0
浦东
后端工程师
私信 提问
加载中

评论(0)

Android程序员必知必会的网络通信传输层协议——UDP和TCP

本文原文由作者“zskingking”发表于:jianshu.com/p/271b1c57bb0b,本次收录有改动。 1、点评 互联网发展至今已经高度发达,而对于互联网应用(尤其即时通讯技术这一块)的开发者来说,网络...

JackJiang2011
2019/01/10
0
0
Android程序员必知必会的网络通信传输层协议——UDP和TCP

1、点评 互联网发展至今已经高度发达,而对于互联网应用(尤其即时通讯技术这一块)的开发者来说,网络编程是基础中的基础,只有更好地理解相关基础知识,对于应用层的开发才能做到游刃有余。...

首席大胸器
2019/01/10
78
0
知乎技术分享:知乎千万级并发的高性能长连接网关技术实践

本文来自知乎官方技术团队的“知乎技术专栏”,感谢原作者faceair的无私分享。 1、引言 实时的响应总是让人兴奋的,就如你在微信里看到对方正在输入,如你在王者峡谷里一呼百应,如你们在直播...

首席大胸器
2019/09/05
449
0
HTTP详解(一)

一、socket介绍二、TCP FSM有限状态机三、http相关概念四、http服务器程序 一、socket介绍 1.socket: C/S Client:发起应用请求的程序 Server:响应请求(提供服务)的程序 LISTEN:Socket c/s双方...

MT_IT
2017/11/22
0
0
迈向高阶:优秀Android程序员必知必会的网络基础

1、前言 网络通信一直是Android项目里比较重要的一个模块,Android开源项目上出现过很多优秀的网络框架,从一开始只是一些对HttpClient和HttpUrlConnection简易封装使用的工具类,到后来Goo...

首席大胸器
2018/09/17
248
0

没有更多内容

加载失败,请刷新页面

加载更多

java关键字 —— new、this、static

  java关键字,也叫保留字(50个),是java有特殊意义的标识符,不能用作参数名、变量名、方法名、类名、包名等。   现在我们讲讲其中三个关键字的使用吧~~~ 一、new关键字 1. 用途:新建...

osc_s2b5kacl
10分钟前
11
0
java 集合框架的工具类Collections

sort(),max(),binarySearch(),fill() public class CollectionsDemo { public static void main(String[] args) { replaceAllDemo(); } public static void replaceAll......

osc_r9yyhhqz
11分钟前
15
0
创龙基于Xilinx Kintex-7系列高性价比FPGA开发板散热风扇接口、SATA接口

处理器 Xilinx Kintex-7系列FPGA处理器,芯片型号为XC7K325T-2FFG676I,兼容XC7K160T/410T-2FFG676I,高达326K逻辑单元,840个DSP Slice,硬件如下图: 散热风扇接口 开发板引出1个散热风扇接...

Tronlong创龙
12分钟前
25
0
【经验分享】学习Java的好书有哪些?Java书籍清单

Java书籍是程序员学习提升技能的重要学习渠道,通过书籍Java程序员可以学习当前流行、重要的相关技能。经典的书经受时间的考验,随着岁月的流逝变得越来越重要,让我们不断的学习和进步。 为...

osc_b1kaj6np
13分钟前
18
0
java Collections的reverseOrder(),SynList()

Collections的reverseOrder(比较器)返回相反的比较器,可以逆转比较器。 SynList()可以让非同步变成同步,底层实现synchronized(){}。 swap交换元素位置。 Collections.shuffle()随机重新排序...

osc_2gkfj43j
14分钟前
17
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部