特别鸣谢
郑烇老师
大佬的笔记:
本来加了索引的 但是不知道为嘛刷新就都没有了。。。。等我再研究研究 会继续优化一下排版
之后的网络层,链路层可能不会这么勤更新了 整个大的架构差不多就是这样了hh
5.20优化 内化知识成为自己的体系
0.牢景前言碎碎念
首先要搞明白,传输层的核心目的是什么,是服务于进程的通信。
计算机网络中实际进行通信的实体,是位于通信两端主机中的进程。
好了 我们有了需求,就要想办法解决。
根据应用需求的不同,运输层为应用层提供了两种不同的运输层协议 TCP,UDP
应用层的信息就是通过这些协议的封装,成为数据报往下层传递。
这是整体的框架。
接下来我们看细一点。
不妨自问? 应用层数据是怎么封装成TCP/UDP的?
对方接收到数据报,又是怎么区分数据属于那些不同的应用进程?
用户与服务器之间,数据又是怎么控制传输的?TCP怎么基于不可靠的IP协议,实现可靠传输的? 传输层连接如何确立? 流量控制,应用控制的机理又是什么?
能解答这些问题 ,才说明你有了基础。
而这三行问题 也是有层次的 。
这个思维图 ,概括了所有层次
我们逐步展开
*1我们到底传的是什么
*2过程的细节
*3封装的具体结构
*4传输的过程中发生了什么
*5例子 DNS解析的发送和确认过程
不同的应用进程的数据被封装到一个TCP报文段里 -----多路复用。相应的 ,接收端将一个TCP报文段的载荷部分读取出来,匹配到不同的应用进程------解复用
具体怎么实现的 socket
1.概念和传输层服务
可拱选择的传输层协议 TCP或UDP
传输协议运行在端系统
为运行在不同主机的应用进程提供逻辑通信
-
2.多路复用和解复用
复用:将多个应用进程的socket封装成TCP/UDP
本来有多个进程之间的通讯线路的,但通过复用(标识两者之间)只需要一条线路即可
解复用: 将收到的报文端根据socket比对匹配到相应的进程
UDP多路解复用:
创建套接字(接收端本地的二元组)—>收到UDP报文段---à比对
-
3.UDP
-
特点
-
·尽力而为(可能会丢失数据,报文段乱序)
·无连接(每一个UDP报文段都被独立地处理)
·如果要在UDP上实现可靠传输呢?{在应用层增加可靠性 应用特定的差错恢复}
也就是说:仅仅在IP上增加了复用和解复用功能
事务性:一次往返就结束
-
-
报文格式
-
校验和是验证报文传输过程中有没有出错,如果发现校验不对,那么这个UDP报文会被丢弃
在计算校验和的时候,需要在UDP数据报之前增加12字节的伪首部,伪首部并不是UDP真正的首部。只是在计算校验和,临时添加在UDP数据报的前面,得到一个临时的UDP数据报。校验和就是按照这个临时的UDP数据报计算的。伪首部既不向下传送也不向上递交,而仅仅是为了计算校验和。这样的校验和,既检查了UDP数据报,又对IP数据报的源IP地址和目的IP地址进行了检验。
UDP报文的头部小,固定的8个字节的头部,如上,64 bit。载荷即有效传输的数据部分占比大
具体校验的算法: 进位回滚,取反码(原理 :源码+反码全为1)
-
4.RDT的具体实现
RDT在有些网络中在网络层实现,通常是由TCP在传输层实现
要向上层应用提供可靠的服务,但是所依赖的下层服务却是不可靠的 (best effort)。
思路
渐进地开发RDT:先假设下层是完全可靠的,再逐个去掉假设,变成不可靠的,从而处理这个不可靠,再将其变成可靠,逐个进行,直到所有假设都去掉
RDT 1.0
下层完全可靠
协议:wc 爽了 直接他宝贝的封装解封装完活!
RDT 2.0
下层信道出错,发生比特翻转
对他使用“校验和”吧!
- 发送方要编码检错,接收方要解码校验
- 接收方要告诉发送方,是正确的ACK Acknowledgment,还是错误的NAK Negative Acknowledgment
- 发送方要保存副本,ACK则无需处理,等待上层有没有新的调用,NAK则重新发送副本(检错重传)
RDT 2.1
如果ACK也是错的呢?
你发个乌拉乌拉 ,校验和不通过了,bbq了
- 因此对发送的packet编号0和1【在01之间切换即可】,发送方先发送p0
- 接收方返回的信息ACK出错了,发送方无法识别,则发送方认为是NAK,再发一次p0
- 接收方本来在等待编号1,但收到相同编号的内容,因此知道是ACK发送失败,因此将收到的重复信息丢弃,但仍然再返回ACK确认
停止等待协议 stop-and-wait protocol :
每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。
RDT 2.2
无NAK 协议
取消NAK,而是对ACK编号,使用前一个分组(即最后一个正确接收的分组)的ACK作为该分组的NAK
这样可以为后续一次发送多个分组做好准备(埋下伏笔咯~~~)
RDT 3.0
我分组丢失了咋办? 我的青春小鸟一去不会头~~
会产生死锁
说白了 双方你等我 我等你。。
超时重传机制:
重传时间一般设置为比正常一个往返稍长一点的时间,一旦超过这个时间,一般就能确定分组丢失,然后重传即可
数据链路层的timeout一般是确定的,因为就是在两个节点之间传输
而传输层的timeout是自适应的,即需要根据情况调整,因为中间可能跨越的节点数目会变化
如果是ACK丢失了,那么重传会导致数据重复问题,但接收方可以根据分组序号知道重复,从而丢弃即可
设置一个合律的timeout很重要,如果设置时间太短了,也能正常工作,但会导致分组的发送和应答重复,效率低,
过早超时 重复发送 利用率反而降低
虽然3.0解决了一切问题 但是整个架构思路还是依托于停止等待协议。
但停止等待协议的效率很低,特别是在信道容量(同时能容纳的“车“的数量,等于TR,R是带宽,T是信道从头到尾传输的时间)很大时,就像告诉公路很长,其中同一时间可以容纳很多车辆前后排列,但如果一次仅仅一辆车在行驶,行驶出高速公路后再让下一辆车上高速,显然效率太低了
来来来,升级一下核心装备
流水线协议
流水线协议 pipeline protocol :一次发送多个未经确认的分组
滑动窗口协议
Sliding-window protocol
一些概念:
发送缓冲区:
长度为发送窗口后沿的最大限 落入缓冲区的分组可以被发送 保证重发时可以找到分组
大小:一次最多可以发送的未经确认的分组
发送窗口:里面是已发送但未确认的报文段
接收缓冲区=等于接收窗口
累积确认机制:
比如服务器接收到0 1分组 ,这个时候它直接发ack1就可以 ack0不用发,因为一定已经收到了。
Go-Back-N
接收窗口的大小为一 ,意味着不能发送窗口以外的分组 ,若是收到,则直接丢弃,发送ackx(采用累积确认) 丢失分组的计时器会超时timeout
注意:GBN中只有一个计时器,即在滑动窗口大小从0变成1时启动一个计时器,同时也只需要对最小序号的分组计时即可。当收到最小序号的ACK时,那么会把计时器重置,发送窗口右移动;如果收到ACK后,窗口大小变成0,那么关闭计时器;在超时重发时也会重置计时器
Selective repeat
由于sw大于1 ,意味着可以乱序接收,只要分组落在sw里面就行,同样意味着它的返回机制不是累积确认了,ackx只是意味着收到了x分组,不代表之前的全部ok了
接收窗口在后延的分组被确认的时候开始移动
【注意:SR的每一个分组发送后都会有一个计时器分别计时,因此较为复杂】
窗口后延移动的条件 收到老分组的确认
-
5.TCP
-
-
特点
-
·点对点
·可靠的,按顺序的字节流
·管道化
·发送和接收缓存
·全双工数据 数据流双向移动
·面向连接
·有流量控制
单工就是在只允许甲方向乙方传送信息
-
-
TCP报文段结构
-
TCP头部长度至少20 B,但还有一些可选项以一起构成头部,其中的首部长度就记录了头部的长度,用以区分出数据部分
序号 seq 序号指的是一个TCP数据报的数据部分的第一个字节在整个字节流中的偏移量,字节为单位。
确认号 ack 指确认n-1及以前的字节,比如ACK 555,那么就表示554及之前的都已经收到了,期待555
Q:接收方如何处理乱序到达的Segment?
A:TCP规范中没有规定,由TCP的实现者做出决定,可以缓存,也可以直接抛弃
TCP动态自适应地改变计时器的时间TCP可靠数据传输
TCP采用pipe-line 是GBN和SR的混合体
-
TCP可靠数据传输
流水线机制
单一重传计时器
累积确认模式
触发重传:
- 超时:只发生最早的那个未确认的段,即发生超时的这个段
【超时定时器是比较保守的,在4倍偏差,因此如果超时,可以有极大的把握确定报文丢失】
- 重复的ACK:收到了1个正确ACK,然后又收到3个冗余的重复ACK,那么重传,而此时超时定时器还没超时,因此称为快速重传
一些现象
-
-
仔细聊聊累积确认机制
-
1.到了一个报文段后等待500 ms,如果第二个报文段在500 ms没来,那么发送第一个的ACK
2.如果上面等待过程中第二个连续的报文段到达,立即发送第二个报文段的累计确认,同时确认两个报文段
3.乱序到达,需要的一个报文段比如第一个字节位置为y0,而到达了第一个字节大于y0的,说明乱序,立即发送重复的ACK=y0,表示对y0的期待,让发送方重发
-
-
TCP快速重传机制
-
Q:为什么是三次?
A:因为无法判断是因为乱序还是丢失,重传1到2次更可能是乱序,3次及以上更可能是因为丢失
-
-
TCP流量控制
-
接收方返回ACK时在receive window中记录其空闲的buffer的大小,从而发送方会限制其发送缓冲区中未确认的字节个数≤receive window值
piggyback捎带技术,即发送方和接收方是随时变化的,客户端发送数据给服务器,服务器也会发送数据给客户端,所以如果发送一次对方要返回一个确认,然后又发送数据回来,会比较麻烦,因此可以将确认放在数据中一起发送回来,即捎带
连接建立的本质:知道和要对方通信,准备好资源,控制变量做置位(特别是连接的初始序号#seq,对方的receive buffer的大小)
为什么两次握手不可行?
会出现半连接,接收老数据的bug
看图
-
-
-
三次握手
-
-
1.客户端发送 连接请求SYN=1并携带它将要从序号为x处开始传Seq=x
2. server需要对这个信息进行ACK,ACKNum=x+1【期望x+1及之后的数据】
同时需要SYN=1并将自己从序号为y处开始传Seq=y告诉client
3. 然后client对server的y进行确认ACKNum=y+1【期望y+1及之后的数据】
同时进行第一次数据传递
Q:会不会在三次握手的第二步服务器就会分配资源?
A:会分配,会保留一段时间直到确认这个ACK不会再建立了(SYN泛洪攻击,DDoS)
再看半连接
如果后续收到了在网络中拥塞而迟到的客户端连接请求 ,服务器会发送确认连接,但是客户端自己并没有对服务器发送过连接 ,所以直接丢弃,排除半连接
延迟到达的data
到达服务器,但服务器之前并没有客户端建立连接 直接丢弃
第三种情况
假设客户端使用555端口与服务器80端口建立连接,在第二种情况的基础上,如果data卡了很久才到达服务器,而此时正好客户端又用555
·如果序号都是从0开始的话,那么这个老数据会被当成当前需要的数据,而产生错误。
·因此每次选择随机的开始序号,可以避免老的滞留的数据对连接的影响,比如老数据从x开始,而新的开始序号是x+1,那么老的数据肯定会被抛弃,因为都不在连接的序号范围内(≥x+1)
·当然有可能随机选择的序号正好又包含老数据,但概率极小,那这就没有办法了👉网络不能解决所有问题
-
-
-
四次挥手
-
-
对称释放,并不完美
四次挥手是由于 TCP 的半关闭(half-close)特性,TCP 提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力
[结束发送指的是不再发送数据,但可以对对方的请求作出应答]
TCP 连接的释放需要发送四个包(执行四个步骤),因此称为四次挥手(Four-way handshake),客户端或服务端均可主动发起挥手动作
1)第一次挥手:客户端发送一个 FIN 报文(请求连接终止:FIN = 1),报文中会指定一个序列号 seq = u。并停止再发送数据,主动关闭 TCP 连接。此时客户端处于 FIN_WAIT1 状态,等待服务端的确认。
FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认;
2)第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT状态。
CLOSE-WAIT - 等待从本地用户发来的连接中断请求;
此时的 TCP 处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2(终止等待 2)状态,等待服务端发出的连接释放报文段。
FIN-WAIT-2 - 从远程TCP等待连接中断请求;
3)第三次挥手:如果服务端也想断开连接了(没有要向客户端发出的数据),和客户端的第一次挥手一样,发送 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态,等待客户端的确认。
LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认;
4)第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答(ack = w+1),且把服务端的序列值 +1 作为自己 ACK 报文的序号值(seq=u+1),此时客户端处于 TIME_WAIT (时间等待)状态。
TIME-WAIT - 等待足够的时间以确保远程TCP接收到连接中断请求的确认;
注意 :这个时候由服务端到客户端的 TCP 连接并未释放掉,需要经过时间等待计时器设置的时间 2MSL(一个报文的来回时间) 后才会进入 CLOSED 状态(这样做的目的是确保服务端收到自己的 ACK 报文。如果服务端在规定时间内没有收到客户端发来的 ACK 报文的话,服务端会重新发送 FIN 报文给客户端,客户端再次收到 FIN 报文之后,就知道之前的 ACK 报文丢失了,然后再次发送 ACK 报文给服务端)。**服务端收到 ACK 报文之后,就关闭连接了,处于 CLOSED 状态。**因此服务器到客户端的连接关闭,整个 TCP 连接关闭
两次挥手就可以释放一端到另一端的 TCP 连接,完全释放连接一共需要四次挥手。
举个例子:A 和 B 打电话,通话即将结束后,A 说 “我没啥要说的了”,B 回答 “我知道了”,于是 A 向 B 的连接释放了。但是 B 可能还会有要说的话,于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”,A 回答“知道了”,于是 B 向 A 的连接释放了,这样整个通话就结束了。
- 拥塞控制原理
当分组经过了很多路由器,但在后面的一个路由器被抛弃了,那么它在前面所做的努力都会被浪费,这在网络拥塞时更加可惜,因为资源有限,有限的资源还被浪费了
- TCP 拥塞控制
端系统自己感知拥塞,网络核心负担低
每收到一个 ACK,拥塞窗口加 1 == 下一次的拥塞窗口是上一次的两倍
初始速率很慢,但是快速攀升
AI Additive Increase 加性增:到达 SS 的阈值后,每个RTT将 CongWin 增大一个 MSS 线性地探测-----拥塞避免阶段
MD Multiplicative Decrease 乘性减:
当发送超时后,将 CongWin 降为 1 MSS,开始 SS 并将 CongWin / 2 作为 SS 倍增的阈值。
当收到 3 个冗余 ACK 时,直接将阈值降为 CongWin / 2,并将 CongWin 设置为 阈值 + 3【+3是因为返回 3 个 ACK 所以后面有三个已经确认了】,然后直接线性增加 1【此时 CongWin > 阈值】,而无需从 1 开始 SS。
当收到重复 ACK 时,什么都不做,只是对重复的个数进行计数,为上面的情况做好准备