加油!偷博仔
今天的看到的诗,是灰色的
天是灰色的
路是灰色的
楼是灰色的
雨是灰色的
在一片死灰之中
走过两个孩子
一个鲜红
一个淡绿
————《感觉》1980年7月
进入正题
一、 TCP:面向连接的传输
1.TCP:概述 (RFCs: 793, 1122, 1323, 2018, 2581)
Explanation:
·
所谓没有报文边界:
发送方发两个小报文,也许接收方收到1个大的报文,或者反过来。
发送和接收缓存,
为了超时重发或者检错重传,匹配Send和receive的速度不一致
·
MTU:
Maximum Transmission Unit,最大数据传输单元,网络传输最大报文包;以太网MTU最大值是1500B
MSS:
Maxitum Segment Size应用进程发给传输层TCP实体的报文段,要根据MSS的大小进行切分和加TCP头部信息,变成TCP报文段(segment)
·
所以,(Message 转换成字节流,再被划分成一个个的MSS)
MSS+TCP头部信息+IP头部信息 <= MTU(比如以太网MTU1500B),(“于是就不存在一个分片的问题?”什么分片…)
·
否则,如果要发送的IP数据报比数据链路层的MTU大,则无法发送该数据报。
还可以参考一下这位网友的分享:MSS与MTU的关系
2.TCP报文段结构
Make some explanation:
16bits 源端口,16bits目标端口
32 bits 序号、确认号。
所以,聪明的,同理可得:可选项32bits;校验和等等16bits
字节序号:
对于应用层交下来到Message,划分层一个个的MSS,每一个TCP报文段(segment)的body部分,就是载荷部分(对应MSS),而载荷部分第一个Byte(字节)在整个字节流的offset(偏移量) 就是字节序号
3.TCP 序号, 确认号
接收方处理乱序的segment 可以缓存也可以drop,没有规定。取决于…
Explanation:
- Host A → Host B Seq=42, ACK=79, data = ‘C’:
HostA,商量的初始序号是Seq = 42,并且希望Host B 初始序号从 79号开始,要求回显字节C- 接着Host B → Host A Seq=79, ACK=43, data = ‘C‘:
由于此前Host B 收到了Seq42,处理完后确认ACK=43。同时ACK=43说明Host B已经收到42及以前,并且希望Host A从43开始。
…于是就这样了
4.TCP往返延时(RTT)和超时
设置和测量/估计RTT都要得当啊。
-
Q: 怎样设置TCP超时?
比RTT要长 但RTT是变化的
太短:太早超时 不必要的重传
太长: 对报文段丢失反应太慢,消极 -
Q:怎样估计RTT?
SampleRTT:测量从报文段发出到收到确认的时间
如果有重传,忽略此次测量
SampleRTT会变化,因此估计的RTT应该比较平滑
对几个最近的测量值求平均,而不是仅用当前的SampleRTT
TimeoutInterval是适应性的测量与计算
当前EstimatedRTT的计算:
`“EstimatedRTT = (1-α)EstimatedRTT + αSampleRTT” :
等号左边,是当前的均值RTT,等号右边EstimatedRTT是最近之前的均值RTT, 每隔一个采样时间之前,要再×一个(1-α),给当前均值的贡献,成指数下降。
`
Estimated :adj.估计的。
这个DevRTT(Deviation RTT)很类似标准差,是SampleRTT和EstimatedRTT之间的偏差值/变化值
DevRTT = (1-β)DevRTT + β(|SampleRTT-EstimatedRTT|) :计算平滑RTT和真实的差距(加权移动平均)
接下来看TCP这么做RDT的
二、TCP:可靠数据传输
TCP在IP不可靠服务的基础上建立了rdt
- 管道化的报文段 (• GBN or SR )
- 累积确认(像GBN)
- 单个重传定时器(像GBN)
- 是否可以接受乱序的,没有规范
通过以下事件触发重传
- 超时(只重发那个最早的未确认段:又像SR)
- 重复的确认
- 例子:收到了ACK50,之后又收到3 个ACK50(冗余确认)
首先考虑简化的TCP发送方: (下面第1点)
- 忽略重复的确认
- 忽略流量控制和拥塞控制
1.TCP 发送方(简化版
我对下图的Explanation:
·
最初,建立TCP连接。从虚线开始,有一个初始化的Next序号和SendBase,
(作为开始的发送方,首先发送的字节序号都是从,初始化的序号开始发的)
·
然后就wait for event,
再顺时针看。
于是wait到了,应用进程来了data,就创建Segment、发送窗口前沿seq。
再交到下层进行ip封装数据报和发送
发送窗口前沿滑动:(NextSeqNum = NextSeqNum + length(data))
未计时,就计时开始
·
如果timeout,就只传送具有最小序号的未确段
像SR,不是将所有未确认的都传一遍
`
当ACK received,且ACK的值是y,
如果y > SendBase,那么SendBase = y,
相当于发送窗口后沿向前滑动到位置y,
最后有个对定时器的操作,看图吧
1.1TCP发送方事件:(ppt的对上图的Explanation)
从应用层接收数据:
- 用nextseq创建报文段
- 序号nextseq为报文段首字节的字节流编号
- 如果还没有运行,启动定时器
- 定时器与最早未确认的报文段关联
- 过期间隔:TimeOutInterval
超时:
重传后沿最老的报文段
重新启动定时器
收到确认:
- 如果是对尚未确认的报文段确认
- 更新已被确认的报文序号 如果当前还有未被确认的报文段,重新启动定时器
再来欣赏一下实现1.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 */
/*注释:• SendBase-1: 最后一个累积确认的字节例:
• SendBase-1 = 71;
y= 73, 因此接收方期望73+ ;
y > SendBase,因此新的数据被确认
*/
最后再来一张图
对顺序收到的最高字节确认;
2.产生TCP ACK的建议 [RFC 1122, RFC 2581]
3.快速重传
快速重传:在定时器过时之前重发报文段
通过重复的ACK来检测报文段丢失
- 发送方通常连续发送大量报文段
- 如果报文段丢失,通常会引起(收到)多个重复的ACK
如果发送方收到同一数据的3个冗余ACK,(如下图三个冗余ACK50),
- 重传最小序号的段:
- 它假设跟在被确认的数据后面的数据丢失了
• 第一个ACK是正常的;
• 收到第二个该段的ACK,表示接收方收到一个该段后的乱序段;
• 收到第3,4个该段的ack,表示接收方收到该段之后的2个 ,3个乱序段,可能性非常大
段丢失了
3.1快速重传算法:
dup :duplicate :adj.完全一样的、冗余的
三、TCP:流量控制
接收方控制发送方,
不让发送方发送的太多、太快
防止让接收方的缓冲区溢出
TCP套接字的接收缓冲区:TCP socket receiver buffers
然后TCP是全双工的,于是:
- 接收方在其向发送方的TCP段头部的rwnd字段“通告”其空闲buffer大小。
(不是单独发一个确认信息,而是在“寄快递的盒子上做了个小标注free buffer space”)- RcvBuffer大小通过socket选项设置 (典型默认大小为4096 字节)
- 很多操作系统自动调整RcvBuffer
- 发送方限制未确认(“in-flight”)字节的个数 ≤ 接收方发送过来的 rwnd 值
保证接收方不会被淹没
回顾一下接收窗口和接收缓冲区(Receive Window && Receive Buffer field)
四、TCP:连接管理
在正式交换数据之前,发送方和接收方握手建立通信关系:
- 同意建立连接(每一方都知道对方愿意建立连接)
- 同意连接参数
1.同意建立连接
2次握手的失败场景:
半连接,
左边客户主机进程,由于acc_conn(x)超时,重传了新的连接请求(req_conn(x)),
导致服务器主机进程维护了一个半连接
2.TCP 3次握手 (2次握手解决方案)
TCP中有个标志位SYN。
SYN = 1 代表连接请求
Seq = x 代表从x字节开始传
一般第一次数据传递和第三次握手是一起的。
2.1 三次握手解决:半连接和接收老数据问题
采用初始化序号作为TCP段的序号,而不采用固定的序号:
就可以
有效避免
老的连接的数据
对
新的连接的数据
造成干扰
2.2三次握手: FSM(Finite State Machine)
寄几看看叭~
3.TCP: 关闭连接
- 客户端,服务器分别关闭它自己这一侧的连接 (两个方向的连接单独拆除)
发送FIN bit = 1的TCP段 (FIN = 1表示关闭连接,) - 一旦接收到FIN,用ACK回应
接到FIN段,ACK可以和它自己发出的FIN段一起发送 - 可以处理同时的FIN交换
有些好玩的事情,
要是FIN的确认没收到咋搞,?
要是FIN根本没法过去咋搞,?
要是有人伪造FIN发送给对方咋搞,?
哈哈哈
TCP连接的释放,并不完美,采用了计时器的机制来断开连接。
本篇结束