tcp成块数据流
引言
TCP使用【滑动窗口】协议进行流量控制。
正常数据流
从主机A发送数据到主机B,观察书中图20-1,可以看到主机B并不是对每个请求报文都做出确认,而是累计确认。 具体何时发送确认ack,则和delayed ack的时钟周期相关。delayed ack的时钟周期结束,则发送ack,此时将对所收到的全部数据发送 一个ack。图20-2也类似,同样是累计确认。
快的发送方和慢的接收方
图20-3表示了快发和慢收的报文流程。与前面不同的是,当接收方来不及处理收到的数据而导致接收缓冲区满时, 回复的ack中窗口大小为0,此时发送方收到此确认报文后,不再发送数据,等待服务器发送windwo update报文(服务器缓冲区数据被取走,产生了空闲空间时 则发送窗口更新报文,同时客户端也会主动探测窗口)。
滑动窗口
可以将发送发送的数据分为如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
发送并确认 发送但未确认 能够发送 不能发送直到窗口移动
窗口左右边界的相对运动决定了窗口的大小,左右边界的相对移动有三种形式:
- 【窗口合拢window close】:左边界相对向右移动,发生在数据被发送且被确认
- 【窗口张开window open】:右边界向右移动,发生在接收端读取了发送的数据,释放了接收缓冲区
- 【窗口收缩window shrink】:右边界向左移动,RFC强烈反对这种形式。
左边界不会向左移动,当收到小于窗口左边界的ack值,会直接丢弃。 左边界和有边界重合时,称为0窗口。停止发送数据。
一个例子
图20-6展示了发送过程中滑动窗口是如何动态变化的。 发送方收到的确认报文,其中既有ack又有窗口大小,ack决定了左边界向右移动,窗口大小决定了新的右边界。 【窗口的右边界不能向左移动,为什么?】
窗口大小
由接收方提供的窗口大小由接收进程控制,窗口大小影响TCP性能。 接收缓存的大小是该连接上所能通告的最大窗口大小。
一个例子
通过调整服务器的接收缓存大小,观察窗口变化时的逻辑流程。
PUSH标志
PUSH Flag是由发送者发出,用来通知接收者将它所有收到的数据推送给应用进程。 这些数据包括与PUSH一起传送的数据以及接收方TCP已经为接收进程收到的其他数据。
在最初的TCP实现中,允许通过编程接口来使得应用程序告知TCP何是发送PUSH Flag。 在一个交互程序中,当客户都安发送一个命令到服务器,客户端将设置PUSH Flag,并等待对方响应。 通过允许应用程序通知TCP设置PUSh标志,客户进程不希望因等待额外数据而导致数据在TCP buffer中滞留, 接收方收到带PUSH标志的报文,表示将收到的数据立即发给应用程序而不必等待是否由后续数据到达。 【怎们感觉和URG标志的含义相同了,建议和bilibili的计算机网络视频对照着看】
今天大多数的API不再提供编程接口来使得应用程序设置PUSH标志,而应该主动实现该何时设置此标志。
如果待发送数据将清空发送缓存,大多数的Berkeley实现将自动这是PUSH标志。这表明通常当应用程序write操作时会设置PUSH标志, 因为写时数据将被发出。
例子
在图20-1中,刚建立连接后,发送的每个数据包都带有PUSH标志,因为每个数据段的发出都会清空发送缓冲区。 在图20-7中,在发送第四个报文段时才带上PUSH标志,因此此时已到达发送缓冲区的最大值,肯定要将数据发出来清空缓冲区。 在图20-3中,在窗口由0变为4096,发送端再次发送数据时,四次发送每次1024只有第四次才有PUSH标志,因为发送方知道它的发送窗口时4096, 能立即发送四个数据段,因此只有最后一段才由PUSH标志。
慢启动
之前的例子发送方开始发送数据时,总是直接发送多个报文,直到到达窗口大小。 如果两台主机在同一局域网是没问题的,如果中间有路由器或者较慢的网络则会产生问题。 一些中间路由器必须缓存分组,并有可能耗尽存储器的空间。Jacobason 1988证明了这种简单的连接会严重降低TCP的吞吐量。
现在TCP被要求支持“慢启动算法”,它通过观察新分组进入网络的速率应该与接收者返回确认的速率相同而工作。 慢启动给发送端增加了另一个窗口–congestion window拥塞窗口。 当与另一个的主机建立通信时,拥塞窗口为一个报文段(这里是指MSS?),每次一个ACK到达,拥塞窗口加一(线性增加?)。 发送方的发送数据大小由拥塞窗口和通告窗口两个中的最小值控制。 拥塞窗口是发送方使用的流量控制,通告窗口是接收方使用的流量控制。
发送方开始发送一个报文段并等待ACK(这里指最多发送MSS长度的数据?),收到ack时,拥塞窗口增加到2, 两个报文段长度的数据可以被发送。如果后来的ack又被确认,则拥塞窗口增加到4,是一种指数级增长。
当网络容量到达上限时,中间路由会丢弃包数据。这会通知发送方它的拥塞窗口过大。
一个例子
图20-8中先发送一个报文段,然后等待ack,收到ack后拥塞窗口变为2,就连续发送了两个报文段。 再收到一个ACk后,cwnd变为3,可以发送3个报文段。。。
成块数据的吞吐量
观察窗口大小、窗口的流量控制、慢启动对TCP连接吞吐量的影响。 用图20-9动态展示了管道的吞吐量窗口大小变化,看到理想情况下是占用所有的带宽,使得 吞吐量最大利用。
当使用最大吞吐量时,带宽利用达到极限,通道的容量是带宽xRTT,也就是通道的容量,作为窗口的大小。
当数据从高速网络经路由器转发到低速网络,出口数据速率下降,会占用路由器缓存,引起延迟,缓存满时 甚至会丢弃报文段。一条链路中抵达目的地的数据速率是由链路中最慢的那条决定的。
紧急方式
T C P提供了“紧急方式 ( u rgent mode)”,它使一端可以告诉另一端有些具有某种方式的 “紧急数据”已经放置在普通的数据流中。另一端被通知这个紧急数据已被放置在普通数据流 中,由接收方决定如何处理。
可以通过设置 T C P首部(图1 7 - 2)中的两个字段来发出这种从一端到另一端的紧急数据 已经被放置在数据流中的通知。 U R G比特被置1,并且一个 1 6 b i t的紧急指针被置为一个正的 偏移量,该偏移量必须与 T C P首部中的序号字段相加,以便得出紧急数据的最后一个字节的 序号。
紧急方式有什么作用呢?两个最常见的例子是 Te l n e t和R l o g i n。当交互用户键入中断键时, 我们在第2 6章将看到使用紧急方式来完成这个功能的例子。另一个例子是 F T P,当交互用户 放弃一个文件的传输时,我们将在第 2 7章看到这样的一个例子。 Te l n e t和R l o g i n从服务器到客户使用紧急方式是因为在这个方向上的数据流很可能要被客户 的T C P停止(也即,它通告了一个大小为 0的窗口)。但是如果服务器进程进入了紧急方式,尽 管它不能够发送任何数据,服务器 T C P也会立即发送紧急指针和U R G标志。当客户T C P接收到 这个通知时就会通知客户进程,于是客户可以从服务器读取其输入、打开窗口并使数据流动。 如果在接收方处理第一个紧急指针之前,发送方多次进入紧急方式会发生什么情况呢? 在数据流中的紧急指针会向前移动,而其在接收方的前一个位置将丢失。接收方只有一个紧 急指针,每当对方有新的值到达时它将被覆盖。这意味着如果发送方进入紧急方式时所写的 内容对接收方非常重要,那么这些字节数据必须被发送方用某种方式特别标记。我们将看到 Te l n e t通过在数据流中加入一个值为 2 5 5的字节作为前缀来标记它所有的命令。
|