在 TCP 进行数据传输时, 可以分为成块数据流和交互数据流两种, 如果按字节计算, 成块数据与交互数据的比例约为 90% 和 10%,TCP 需要同时处理这两类数据, 且处理的算法不同.
书籍本章中以 Rlogin 应用为例观察交互数据的传输过程. 提示经受时延的确认是如何工作以及 Nagle 算法怎样减少了通过广域网络传输的小分组的数目.
交互式输入
经受时延的确认
上图第二, 三个报文段可以合并 --- 按键确认和按键回显一起发送. 这种技术叫做经受时延的确认.
通常 TCP 在接收到数据时并不立即发送 ACK, 相反, 它推迟发送, 以便将 ACK 与需要沿该方向发送的数据一起发送(有时这种现象为数据捎带的 ACK). 绝大数实现采用的时延为 200ms, 也就是说, TCP 将以最大 200ms 的时延等待是否有数据一起发送.
ACK 延时等待时间不大于 TCP 定时器的原因:
假如 TCP 使用 200ms 的定时器, 该定时器将相对于内核引导的 200ms 固定时间溢出, 由于将要确定的数据随机到达, TCP 将在下一次内核的 200ms 定时器溢出时得到通知, 所以 ACK 实际等待的时间为 1~200ms 中任一刻.
Nagle 算法
Nagle 算法要求 TCP 连接上最多只有一个未被确认的未完成小分组, 在该分组确认到达之前不能发送其他的小分组. 相反, TCP 收集这些少量的分组, 并在确认到达时以一个大的分组发出去.
流程:
(1)发送端 TCP 将从应用进程接收到的第一数据块立即发送, 不管其大小, 哪怕只有一个字节.
(2)发送端输出第一块数据后开始收集数据, 并等待确认.
(3)确认未达到时, 若收集数据达到窗口的一半或一个 MSS 段, 立即发送.
(4)确认到达后, 把缓冲区中的数据组成一个 TCP 段, 然后发送.
TCP 的成块数据流 https://www.cnblogs.com/zhoudayang/p/5281820.html
1. 滑动窗口协议
TCP 滑动窗口的可视化表示
我们将字节从 1 到 11 进行标号, 接收方通告的窗口称为提供的窗口, 它覆盖了第 4 字节到第 9 字节的数据, 且通告窗口大小为 6. 发送方计算接收者的可用窗口, 以便确定有多少数据可以被立即发送. 当接收方确认数据后, 这个滑动窗口向右移动. 窗口两个边沿的相向运动有以下 3 种情况:
(1)在数据被发送和确认时, 窗口左边沿向右边沿靠近, 称为窗口合拢.
(2)在另一端接收进程读取已经确认的数据并释放了 TCP 接收缓存时, 窗口右边沿向右移动, 称为窗口张开, 此时允许发送更多的数据.
(3)当右边沿向左移动时, 称为窗口收缩. 这种方式不被建议.
2. 窗口大小
接收方的窗口大小通常可以由接收进程控制, 这将影响 TCP 的性能. 对于以太网来说, 默认的 4096 字节并不是最理想的大小, 提高窗口的大小 有时 可以提高网络的吞吐量.
理解窗口
IP 层协议属于不可靠的协议, IP 层并不关心数据是否发送到了对端, TCP 通过确认机制来保证数据传输的可靠性, 在比较早的时候使用的是 send-wait-send 的模式, 其实这种模式叫做 stop-wait 模式, 发送数据方在发送数据之后会启动定时器, 如果数据或者 ACK 丢失, 那么定时器到期之后, 收不到 ACK 就认为发送出现状况, 要进行重传, 这样就会降低了通信的效率.
为了优化上述问题, 比如我让发送的每一个包都有一个 ID, 接收端必须对每一个包进行确认, 这样设备 A 一次多发送几个片段, 而不必等候 ACK, 同时接收端也要告知它能够收多少, 这样发送端发起来也有个限制, 当然还需要保证顺序性, 不要乱序, 对于乱序的状况, 我们可以允许等待一定情况下的乱序, 比如说先缓存提前到的数据, 然后去等待需要的数据, 如果一定时间没来就丢弃掉, 来保证顺序性. 在 TCP/IP 协议栈中, 滑动窗口的引入可以解决此问题.
发送方发送窗口和接收端接收窗口一一对应, 告诉接收端接收区缓存是多少.
理解前提
1,"窗口" 对应的是一段可以被发送者发送的字节序列, 其连续的范围称之为 "窗口".
2, "滑动" 则是指这段 "允许发送的范围" 是可以随着发送的过程而变化的, 方式就是按顺序 "滑动". 在引入一个例子来说这个协议之前, 我觉得很有必要先了解以下前提:
TCP 协议的两端分别为发送者 A 和接收者 B, 由于是全双工协议, 因此 A 和 B 应该分别维护着一个独立的发送缓冲区和接收缓冲区, 由于对等性(A 发 B 收和 B 发 A 收), 我们以 A 发送 B 接收的情况作为例子;
发送窗口是发送缓存中的一部分, 是可以被 TCP 协议发送的那部分, 其实应用层需要发送的所有数据都被放进了发送者的发送缓冲区;
发送窗口中相关的有四个概念: 已发送并收到确认的数据(不再发送窗口和发送缓冲区之内), 已发送但未收到确认的数据(位于发送窗口之中), 允许发送但尚未发送的数据以及发送窗口外发送缓冲区内暂时不允许发送的数据;
每次成功发送数据 (发送且收到了 ACK) 之后, 发送窗口就会在发送缓冲区中按顺序移动, 将新的数据包含到窗口中准备发送;
3.PUSH 标志
发送方使用该标志通知接收方将所收到的数据全部提交给接收进程, 这里的数据包括与 PUSH 一起传送的数据 以及 接收方 TCP 已经为接收进程收到的其他数据.
特点:
(1)通过设置 PUSH 标志, 客户进程通知 TCP 在向服务器发送一个报文段时不要因等待额外数据而使已提交数据在缓存中滞留.
(2)当服务器接收到设置了 PUSH 标志的报文段时, 它需要立即将这些数据提交给服务器进程而不能等待判断是否还会有额外数据到达.
(3)如果待发送数据将清空发送缓存, 则自动设置 PUSH 标志(大多数源自伯克利的实现).
慢启动:
前边的 TCP 连接, 可以看到, 当连接建立后, 发送端总是一下发送好几个分组过去, 直至达到接收方的通告窗口大小为止.
当然这种策略在局域网中, 几乎没有什么问题. 但是如果发送方和接收方之间是一个存在着多个路由器和速率较慢的链路时, 这就可能出现拥塞的问题...
TCP 需要支持一种慢启动的算法. 顾名思义, 是一点点加速, 而不是一次传太多过去.
实现原理: 发送方需要支持一个窗口, 拥塞窗口(congestion window,cwnd). 当 TCP 连接建立好以后, 拥塞窗口被初始化为 1 个报文段, 发送端每收到 ACK, 就在 cwnd 中增加报文段(比如说这个 ACK 是确认的一个报文段, 那么我就增加一个报文段; 下次我就发俩报文段, 收到这俩的 ACK 后, 我就增加到 4 个报文段长度. 有点类似于成倍增加, 这就是慢启动). 那么现在有两个窗口了, 发送端传数据的时候是用拥塞窗口大小还是接收端的通告窗口大小呢? 这里是取两者中较小的一个大小.
来源: http://www.bubuko.com/infodetail-2642043.html