CHARPTER Ⅲ运输层
- 概述和运输层服务
- 多路复用与多路分解
- 无连接传输 : UDP
- 可靠数据传输的原理
- 面向连接的传输 : TCP
- 拥塞控制原理
- TCP拥塞控制
重要参考: https://zhuanlan.zhihu.com/p/34925520
功能和内容
为主机上运行的进程之间提供逻辑通信.
- 划分报文段下发网络层
- 重组为数据交给应用层
针对的是HTTP报文中的DATA部分,这一部分在这里进行分割和进一步下发传输.
运输层和网络层的区别 : 网络层: 不同主机之间的 逻辑通信 : 运输层: 应用进程之间的 逻辑通信
运输层协议能够提供的服务受到底层网络协议的服务模型的限制
在网络层不提供某些服务的情况下,运输层自己提供.
数据报协议:UDP
传输控制协议:TCP
TCP(Transmission Control Protocol,传输控制协议)是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接。 一个TCP连接必须要经过三次“对话”才能建立起来,其中的过程非常复杂, 只简单的描述下这三次对话的简单过程:
1)主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”,这是第一次对话;
2)主机B向主机A发送同意连接和要求同步 (同步就是两台主机一个在发送,一个在接收,协调工作)的数据包 :“可以,你什么时候发?”,这是第二次对话;
3)主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”, 这是第三次对话。
1、UDP是一个非连接的协议,传输数据之前源端和终端不建立连接, 当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。 在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、 计算机的能力和传输带宽的限制; 在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
2、 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等, 因此一台服务机可同时向多个客户机传输相同的消息。
3、UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。
4、吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、 源端和终端主机性能的限制。
5、UDP使用尽最大努力交付,即不保证可靠交付, 因此主机不需要维持复杂的链接状态表(这里面有许多参数)。
6、UDP是面向报文的。发送方的UDP对应用程序交下来的报文, 在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界, 因此,应用程序需要选择合适的报文大小。
小结TCP与UDP的区别:
1、基于连接与无连接;
2、对系统资源的要求(TCP较多,UDP少);
3、UDP程序结构较简单;
4、流模式与数据报模式 ;
5、TCP保证数据正确性,UDP可能丢包;
6、TCP保证数据顺序,UDP不保证。
7 报文格式是一样的?
Ref: https://zhuanlan.zhihu.com/p/24860273
多路复用和分解
端口
进程/服务的标识码,确保数据交付到正确的进程.
端口是16bit的.
套接字(略).TCP将Socket作为连接的基本单位.
报文格式
- 每个数据包都有源IP地址 和目的IP地址
- 每个数据包都携带一个传 输层的数据报文段
- 每个数据报文段都有源、 目的端口号
IP地址在头部,端口在报文段部分.
多路复用
一个服务器分端口同时建立多个连接分别传输不同的 数据报
一个最简单的运输层协议必须提供
- 多路复用/多路分解服务
- 差错检查
UDP
-
发送方
-
从应用进程得到数据
-
附加上为多路复用/多路分解所需的源和目的端口号 及差错检测信息,形成报文段(数据报)
-
递交给网络层,尽力而为的交付给接收主机
-
-
接收方
- 从网络层接收报文段(数据报)
- 根据目的端口号,将数据交付给相应的应用进程
特点
拿到数据就直接传送,不需建立连接也不用维护连接.数据传送完之后直接关闭.
无拥塞控制.
无可靠传输协议
数据报的结构
Check sum
检测收到的报文段的“差错” (例如, 出现突变的比特).
对报文段的所有16比特字的和进行1的补运算.
发送方将计算校验和的结果写入UDP校验和字段中
运算细节:
- 相加
- 进位回卷到低位
- 对1求反
可靠数据传输协议
参考: https://blog.youkuaiyun.com/qq_33936481/article/details/53152903
信息在不可靠信道中的可靠传递.
rdt_send()
:reliable data transformation
udt_send()
:unreliable data transformation.
rdt_rev()
:Receiving from the unreliable path.
deliver_data()
:Send to the upper layer.
用有限状态机 (FSM) 来描述发送方和接收方
Event/Action
事件驱动的状态变化
rdt1.0
- 底层信道完全可靠
- 不会产生比特错误
- 不会丢失分组
rdt2.0
假设
- 有数据错误
- 无丢包
Add
- 差错检测:checksum
- 结果检查反馈:ACK/NAK
- 重传机制
重传:缓存发出但未收到反馈的报文段
此时只要求缓冲区大小=一个报文段.
rdt2.1
- ACK和NAK可能受损
- 比特差错的恢复
- 数据报的编号
用2个序列?
2.1新增了sequence number,同样使用ACK与NAK来确认讯息,封包的号码可以用来确认是否重新传输封包。
例如接收端在等待编号0的封包,结果收到封包1,此时会回传ACK1给来源端,而正在等候ACK0的来源端收到ACK1 表示封包0可能遗失,所以会再重送封包0。
参见:
exp:如果收到了错误的ACK/NAK,直接重传当前报文段会导致接收方可能收到两个相同的报文段.
解决方法:设置序列号,收到重复分组时丢弃.
rdt2.2
- 只使用ACK
- 取消NAK,接收方对最后一个正确收到的分组发送 ACK -减少ACK发送量(?)
- 接收方必须明确指出被确认的分组的序号
- 发送方收到的重复的ACK将按照NAK来进行处理
- 重传正确的分组
Send:
-
如果上一层下发数据:发送[0]
-
等待ACK[0]
-
如果收到ACK但:
- ACK损坏
- 给的是ACK[1]
重发PACK[0]并继续等待
-
如果没有损坏且顺序正确:等待下一个数据PCK[1]下发
Receive:
- 如果收到PAK[0]且正确:
- 解析拼合数据并上传
- 检查checksum
- 送出ACK
- 跳转至等待1的状态
- 如果收到的是PAK[1]或者包损坏:
- 重发ACK(?)
EXP
发送方获得来自上层的数据后,封包(编号为0)发送至接收方,接收方接收到分组后:
1、如果没有损坏,回送ACK分组,并等待编号为1的分组
2、如果损坏,回送NAK分组,并继续等待编号为0的分组
发送方接收到回送分组后:
1、如果没有损坏,且为ACK分组,无任何动作,等待上层协议
2、如果没有损坏,且为NAK分组,重发编号为0的分组
3、如果损坏,无论是ACK还是NAK,重发编号为0的分组
接收方收到分组后(接收方不知道自己的ACK或NAK分组在传输过程中是否损坏):
1、如果没有损坏,且为编号1的分组,回送ACK分组,且等待编号为0分组(循环)
2、如果没有损坏,且为编号0的分组,回送ACK分组,且等待编号为1分组
3、如果损坏,回送NAK分组,等待编号为0分组
为什么会出现重复的分组?假如发送方无误的将分组0发送给了接收方,接收方也发送ACK分组准备接收分组1,但是ACK分组却在传输过程中损坏了,这会导致发送方重发分组0,而不是分组1。
rdt2.2与2.1的区别就在于去掉了NAK,而在ACK分组中显式指出分组编号:
发送方获得来自上层的数据后,封包(编号为0)发送至接收方,接收方接收到分组后:
1、如果没有损坏,回送ACK0分组,并等待编号为1的分组
2、如果损坏,回送ACK1分组,并继续等待编号为0的分组
发送方接收到回送分组后:
1、如果没有损坏,且为ACK0分组,无任何动作,等待上层协议
2、如果没有损坏,且为ACK1分组,重发编号为0的分组
3、如果损坏,无论是ACK1还是ACK0,重发编号为0的分组
接收方收到分组后(接收方不知道自己的ACK分组在传输过程中是否损坏):
1、如果没有损坏,且为编号1的分组,回送ACK1分组,且等待编号为0分组(循环)
2、如果没有损坏,且为编号0的分组,回送ACK0分组,且等待编号为1分组
3、如果损坏,回送ACK1分组,等待编号为0分组
rdt3.0
有错误,有丢包(丢PAK和ACK)
丢包的应对:建立time out机制;到时间认为包丢失,申请重传.
特点:
- 加入定时器,在开始等待ACK时开始计时
- 超时处理机制:重发该PAK
EXP
无丢包下:
丢包PAK下:
这里超时是指的ttl内无ACK返回
丢包ACK下:
这里后发的PAK1重复丢弃.
超时过早(指超时后ACK又发了过来):
上面图中rdt_tcv(pkt)/None
就是这种情况.
rdt3.0的性能优化
流水线技术:不经确认发送多个分组
要求双方都有数据缓存机制
一个RTT内能发送三组数据(理想情况下)
工作原理:
- 分组首部使用字段表示序号
- 已被传输但还未确认的分组的许可序号范围可以看作是一 个在序号范围内大小为N的“窗口(window)”
N=未收到ACK的已发送单元+未发送的单元
流水线下的丢失重传方案
- GBN:之后的分组全部重传
- SR:只重传该分组
GBN下 接收方对序号n之前包括n在内的所有分组进 行确认 - “累积 ACK”,对于失序分组直接丢弃,重发按序到达的最高序号分组的ACK.
TCP
特点:
-
面向连接 TCP连接仅存于端系统,中间路由器对此毫不知情
-
全双工服务 可双向同时传输数据
-
点对点连接 仅存在于两个端系统之间,无第三者“插足”
-
三次握手
-
建立连接,协商参数
-
可靠的字节流
-
最大报文段长MSS
应用了上述可靠数据传输协议的运输层协议.
报文头部格式
随便找了一个图
-
srcport/dstport:目标进程的端口号(注意:目标的IP地址已经在上一层头部了)
-
Seq:本报文段所发 送的数据的第一个字节在整个报文字节流中的序号.(所以每个相邻的数据包之间的序号差=长度)
-
确认号:期望收到对方的下一个报文段 的数据的第一个字节的序号(Expected Next)
-
首部长度:指示头部和数据段的区分
-
几个指示位:
- URG:指示紧急报文
- ACK:此时确认号字段有效.
- PSH:收到后直接推送,不在缓存中停留.
- RST:重新建立连接.
- SYN:指示连接请求报文.
- FIN:指示释放连接
-
窗口:窗口字段用来控制对方发送的数据量, 单位为字节。TCP连接的一端根据设置的缓存空间大小确定自己 的接收窗口大小,然后通知对方以确定对方的发送窗口的上限。即双工环境下,发送方和接收方的窗口大小应该一致.
-
CHECKSUM:检验和字段检验的范围包括首部和 数据这两部分。在计算检验和时,要在 TCP 报文段的前面加 上 12 字节的伪首部
-
EMER:紧急指针指出在本报文段中的 紧急数据的最后一个字节的序号.也就是划定紧急内容的大小.
-
长度可变的选项:MSS:MSS 告诉对方 TCP:我 的缓存所能接收的报文段的数据字段的最大长度是 MSS 个字节。
-
PAD:填充头部至4字节整数倍
TCP超时设置和处理:RTT估算
样本RTT:测试报文发出到收到ACK之间的时间,作为间隔时间地方统计样本(忽略重传)
参考RTT平均了近几次的样本,并且每次随着数据更新更新.
E
s
t
i
m
a
t
e
d
R
T
T
=
(
1
−
α
)
∗
O
r
i
g
i
n
a
l
E
s
t
i
m
a
t
e
d
R
T
T
+
α
∗
S
a
m
p
l
e
R
T
T
Estimated RTT=(1-\alpha)*Original EstimatedRTT+\alpha*SampleRTT
EstimatedRTT=(1−α)∗OriginalEstimatedRTT+α∗SampleRTT
α为参考系数.
考虑RTT的波动,估计EstimatedRTT与 SampleRTT的偏差DevRTT
TCP超时设置为 E s t i m a t e d R T T + 4 ∗ D e v R T T EstimatedRTT+4*DevRTT EstimatedRTT+4∗DevRTT
TCP的重传处理
- TCP编号采用按字节编号,而非按报文段编号
- TCP仅采用唯一的超时定时器
NextSeqNum = InitialSeqNum
SendBase = InitialSeqNum
loop (forever) {
switch(event)
event: data received from application above
create TCP segment with sequence number NextSeqNum
if (timer currently not running)
start timer
pass segment to IP
NextSeqNum = NextSeqNum + length(data)
event: timer timeout
retransmit not-yet-acknowledged segment with
smallest sequence number
start timer
event: ACK received, with ACK field value of y
if (y > SendBase) {
SendBase = y
if (there are currently not-yet-acknowledged segments)
start timer
}
} /* end of loop forever */
ACK丢失:
ACK=100:Host B receives data 92-99, expect 100 next
超时过短导致收到ACK在超时之后:
累计确认:收到非期待的数据包,发送最后一个ACK,避免重传
一样的也是采用的 ACK 机制,但是注意一点的是,并非对于每一个报文段都进行确认,而仅仅对最后一个报文段确认,
ACK丢包
快速重传
超时间隔加倍
每一次TCP重传均将下一次超时间隔设为先前值的两倍
避免过多的超时过短
流量控制
目标:避免接收方缓存区溢出造成丢包
手段:接收方在反馈时,将缓冲区剩余空间的大小填充在报 文段首部的窗口字段中,通知发送方
也就是报文头中的窗口值
接收方的缓存区类似系统中的缓冲区 存在生产者和消费者
连接建立
- 发送连接请求:SYN=1,SEQ=x
- 返回确认:SYN=1,ACK=1,SEQ=y(接收方的缓冲区存储情况),ACK=x+1
- 再次确认:ACK=1,SEQ=x+1(之前的包数据部分是空的),ACK=y+1
连接关闭
- FIN=1,SEQ=x
- 返回ACK=1,SEQ=y,ACK=x+1
此时是半关闭状态.如果还发送数据仍接收.
拥塞控制(不同于流量控制)
过多的源发送了过多的数据,超 出了网络的处理能力
出现的现象:丢包和排队延时++
慢开始/快恢复
- 一开始我们不知道网络中的拥塞情况,我们就发一个数据包
- 如果没有发生拥塞我们成倍的增加发送的数据的数量。
- 当然我们也不能到无休止的增加,这里有一个慢开始门限,到达门限则加法增加,每次加一。
- 这时候如果遇到了拥塞,我们直接跳到第一步,也就是从头开始,并且把慢开始门限调整为拥塞时候的数据量的一半再次开始。
(*) Reno算法
- 当拥塞窗口CongWin小于门限值Threshold时,发送 方处于 慢启动 阶段,窗口以指数速度增大。
- 当拥塞窗口CongWin大于门限值Threshold时,发送 方处于 拥塞避免 阶段,窗口线性增大。
- 当收到 3个重复的ACK 时,门限值Threshold设为拥塞 窗口的1/2,而拥塞窗口CongWin设为门限值 Threshold。
- 当 超时 事件发生时,门限值Threshold设为拥塞窗口 的1/2,而拥塞窗口CongWin设为1个 MSS。
重复ACK的出现:
TCP的公平性
如果K个TCP连接共享同一个带宽为R的瓶颈链路, 目标维持每个连接的平均传输速率为 R/K
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3uYGj0E8-1577344486011)(CHARPTER%20%E2%85%A2%E4%BC%A0%E8%BE%93%E5%B1%82.assets/image-20191214220140061.png)]
但是并行的链接的建立可以获取更多的吞吐量.
TCP的拥塞控制
假定 :
- 假设客户机与服务器间链路传输速率为 R
- MSS大小为S (比特),对象大小为O (比特)
- 没有重传(无丢包和损坏)
- 拥塞窗口大小为W个报文段
- 影响时延的因素
- TCP建立连接
- 数据传输延时
- 慢启动
情况1:服务器在完成窗口 的传输之前就已经收到了窗口中第一个报文段的确认
情况2:服务 器收到窗口中第一个报文段的确认之前已 经将窗口中所有报文段传输完毕