26考研 | 王道 | 第五章 传输层
26考研 | 王道 | 第五章 传输层
文章目录
- 26考研 | 王道 | 第五章 传输层
- 1. 传输层提供的服务
- 2. UDP协议
- 2.1 UDP数据报
- 2.2 UDP检验
- IP首部检验和 与 UDP检验和的区别
- 3.TCP协议
- 3.0 TCP概览
- 面向字节流和面向连接理解
- 3.1 TCP段格式
- 3.2 TCP连接管理
- 1.三次握手
- 1.考察SYN,ACK,FIN,seq,ack_seq
- 2.进程TCP状态的转换
- 3.耗时分析
- 2.四次挥手
- 1.各个数值
- 2.进程TCP状态的转换
- 3.耗时分析
- 3.3 可靠传输和流量控制
- 1.确认号、发送窗口接收窗口
- 2.累积确认
- 3.捎带确认
- 4.超时重传
- 5.快重传、立即确认
- 1.推迟确认的缺点
- 2.快重传、立即确认
- 3.易错点
- 3.4 拥塞控制
- 1.慢开始、拥塞避免
- 2.快重传、快恢复
1. 传输层提供的服务
IP报协议部分TCP是6,UDP是17
2. UDP协议
2.1 UDP数据报
UDP数据报实际最大长度只有65515B这么长,因为IP数据报不拆分的最长长度也就是65535B这么长,还要除去至少20B的IP数据包首部长度,那么剩下的65515B就是UDP数据报的总长度了。
2.2 UDP检验
其实就是UDP对应的差错控制,错了直接扔了,而且不通知发送方
接收方把数据和检验和相加如果得到的不是全1就是错的
刚开始的没有计算过检验和的时候,把检验和当做全0来算
IP首部检验和 与 UDP检验和的区别
两者检验方法一致,需注意一下区别
1.IP首部检验和只检查首部,不检查数据部分
2.IP首部检验和不需要添加伪首部
3.TCP协议
3.0 TCP概览
TCP建立的连接本质上是两台主机的进程之间的通信,而非单纯的主机到主机的连接。
建立连接由客户端发起,释放连接客户端和服务器都可以发起
MSS只是数据部分的大小,不包含首部长度
面向字节流和面向连接理解
面向字节流的理解:不管进程给了TCP多少报文,在它看来都是一连串的字节流,它要做的就是按照MSS把这个字节流拆分开来,然后通通交给接收进程的TCP
TCP与UDP在数据传输方式上的核心差异体现在面向字节流和面向报文的特性上。
- TCP的字节流特性
TCP将应用层传递的数据视为无结构的连续字节序列,发送方会根据网络条件(如MTU限制)自动拆分或合并数据。例如,若应用程序连续发送"Hello"和"World",TCP可能将其合并为"HelloWorld"发送,接收方无法直接区分原始分界点。这种特性导致需要应用层通过特殊分隔符或自定义消息头解决"粘包"问题 - UDP的报文边界保留
UDP严格保留应用层提交的消息完整性。每个UDP数据报(Datagram)都对应一个完整的用户消息,发送方既不拆分也不合并数据。例如,若应用层发送"Hello"和"World",接收方会收到两个独立的数据报,边界清晰。这种特性使UDP天然适合需要消息独立性的场景(如DNS查询)。
- TCP发送过程:
应用层发送"123456789" → TCP拆分为3个段(“1234”、“5678”、“9”) → 接收方缓存重组为完整字节流 - UDP发送过程:
应用层发送两个消息"A"和"B" → 生成两个独立数据报 → 接收方分别读取"A"和"B"
典型应用场景
- TCP适用场景
- 需要数据完整性的场景:HTTP网页加载、电子邮件传输(SMTP/POP3)
- 长连接交互:数据库连接、SSH远程登录
- 流媒体中的可靠性优先场景:直播中的关键帧传输
- UDP适用场景
- 实时性要求高的场景:在线视频会议(如Zoom)、多人在线游戏
- 广播/多播通信:IP电视流媒体、网络时间协议(NTP)
- 简单查询响应:DNS域名解析、DHCP动态IP分配
3.1 TCP段格式
确认号具有累计确认的特性,如果1-2500B都已经接收,3000-4000B也正确接收,返回的确认号是2500,因为还没收到2500-3000B的内容
紧急指针的序号和上面的序号sqe两者的序号不是一套序号,比如上面的序号是2500-3000B,下面的紧急指针的序号可以是100-199,两者没有关联
一个报文段可能既是SYN段又是ACK段,这三个位并不互斥,不是只能成为其中一个
就是接收方的接收缓冲区目前还可以接收多少字节就要满了,然后发送方就会根据这个数来发送,不会发的太多太快
MSS字段的大小只是数据部分的大小,不包含首部
比如MSS为1000,那么数据部分最大就是1000B
同时,TCP连接的双方通过选项字段可以协商MSS大小,并且双方设置的MSS大小可以不一样
比如A给B的报文段MSS设置为1000,那么A给B发的最大就是1000B
B给A的报文段MSS设置为800,那么B给A发的最大就是800B
3.2 TCP连接管理
传送数据的时候
甲是发送方,乙是接收方
甲发的报文seq=102,ack=556,数据部分有100B
那么乙给甲回复的报文seq=556,ack=202
回复的报文就是 seq就是发过来的ack,而回复报文的ack就是发送报文的seq+数据长度,对直接加就行
三次握手建立连接:
1.SYN=1,seq=x
2.SYN=1,ACK=1,seq=y,ack=x+1
3.ACK=1,seq=x+1,ack=y+1
四次挥手释放连接:
1.FIN=1,seq=u
2.ACK=1,seq=v,ack=u+1
3.FIN=1,ACK=1,seq=w,ack=u+1
4.ACK=1,seq=u+1,ack=w+1
1.三次握手
1.考察SYN,ACK,FIN,seq,ack_seq
客户端发送的序号和服务器发送的序号可以相同也可以不同,比如上图,客户端发送的是以666开始的序号,而服务器是以50开始的序号
服务器握手2的ack是确认的客户端的seq=666,所以是发给客户端的是seq+1,也就是667
而客户端握手3的ack确认的是服务器的seq=50,所以发给服务器的是seq+1,也就是51
即虽然握手1,2不能携带数据,但仍然要消耗一个序号
2.进程TCP状态的转换
3.耗时分析
1RTT是一个来回
从客户端来看,由于握手3就可以直接携带数据,所以用户只需要等握手1过去,握手2回来就是了,是1RTT
而服务器则需要等待握手1,握手2,握手3,一共3趟,也就是1.5RTT,也就是连接建立以后才会开始发送数据
核心:
客户端是收到握手2之后才可以发送数据,服务器是收到握手3才可以发送数据
2.四次挥手
1.各个数值
假设客户端是首先发起释放连接的那一方
客户端收到挥手2之后,就不能给服务器发送数据了(因为客户向服务器发送数据的通道已经关闭了,这也是挥手4不能发送数据的原因),而服务器还可以给客户端单向发送数据
挥手1和挥手3实际上可以携带数据,但考试一般默认不携带数据
总结:
其实挥手1,2,3都可以携带数据,就是4不行
而挥手2和挥手3之间的序号的差值取决于挥手2和挥手3中间传了多少的数据
2.进程TCP状态的转换
FIN=1的是挥手1和挥手3
3.耗时分析
等待2MSL是为了防止,客户端收到挥手3,然后发给服务器的挥手4丢失了的这种情况。这时候服务器会重新发送一个挥手3,客户端的计时器也会重置 ,然后客户端重新发个挥手4
3.3 可靠传输和流量控制
注:并不是要接收缓冲区满了才可以交付给应用程序,只要接收缓冲区里面的数据是有序的就可以
TCP滑动窗口协议中,发送方滑动窗口的大小规定了发送方最多能够发送的分组数量,只有窗口滑动了,才能往后继续发。分组重传的最大值也是发送方能发送数组的最大值,因而分组重传的数量最多也不能超过滑动窗口的大小
TCP为每个连接设有一个持续计时器,只要发送方收到对方的零窗口通知,就启动持续计时器。
若计时器超时,就发送一个零窗口探测报文,而对方就在确认这个探测报文段时给出现在的窗口值,如果窗口仍然为0,则发送方收到确认报文段后就重新设置持续计时器
连续收到两个长度为MSS的报文段立即返回ack段是因为 这两个段长度很大,重传代价太高了
1.确认号、发送窗口接收窗口
实际中接收窗口大小rwnd一般为8KB,就是以KB为单位的,但是在这例子中,就是8B,是为了简化理解
其实接收和发送缓冲区其实就是char[]数组而已,10B就是长度为10的char型数组
发送窗口大小必须小于接收缓冲区大小,在本例子中,10B的发送缓冲区只有8B能用做发送窗口
而对于服务器来说,8B的发送缓冲区可以全都用作发送窗口,只要满足比接收缓冲区小就可以,显然8B小于10B,是满足的
重点:
发送窗口大小不能大于发送缓冲区大小,也不能大于接收方的接收缓冲区的大小
实际上,王道这里讲的是socket编程,发送数据和接收数据也确实是用send和recv进行发送和接收的
一个端口可以建立多个TCP连接,只要对应的socket对象不同就行了。每个TCP连接仅支持一对一通信(全双工)
注:
同一端口可以承载多个TCP连接的关键在于四元组的唯一性,而不同的socket对象本质上是对不同四元组的抽象实现
- 四元组的唯一性:
TCP连接的标识是四元组(服务端IP、服务端端口、客户端IP、客户端端口)。只要四元组中任意一个元素不同,操作系统内核就会认为这是两个独立的连接。因此,服务端的一个端口可以与多个客户端的不同端口/IP组合建立连接,每个连接对应一个唯一的socket对象 - socket对象的本质:
Socket对象是操作系统内核中TCP连接状态的抽象。服务端的主监听socket(listen_socket
)仅负责接收新连接请求,而通过accept()
函数生成的每个新socket(client_socket
)对应一个已建立的连接,其内核状态中包含了完整的四元组信息
误区1:端口只能单连接:错误。端口是逻辑概念,内核通过四元组区分连接,而非单纯依赖端口
误区2:客户端端口不可重用:客户端可通过设置SO_REUSEADDR选项重用本地端口连接不同服务端
TCP协议的发送缓冲区,接收缓冲区在建立连接时由操作系统内核分配,大小不固定
发送窗口和接收窗口大小也并不一定要相等,具体大小由操作系统决定
具体发送过程:
发送缓冲区是0,1,2,3,4,5,6,7,8,9,一开始发送窗口是8,然后把0,1,2发送过去了,接收方返回ack=603,表示第600,601,602个字节已经收到了。之后发送缓冲区就把ack之前的数据全都给清理出去了
接下来就是接收方的接收缓冲区只有5字节了,那么发送窗口的大小也必须调整为5,也就是发送窗口大小。到这里就可以体会到最新确认号,最新接收窗口大小了
2.累积确认
发送两个报文段,一个带着3,4一个带着5,6,不管谁先到达,TCP都有办法确认这四个数据应该在的位置,并且返回较大的确认号,也就是返回607,然后会构造一个不含任何数据的ACK段,告诉接收方607这个序号和接收窗口变成1
接下来就是发送方就发只含1B数据的报文段,因为发送窗口只有1这么大,然后接收缓冲区就满了,满了以后要尽快按序交付给应用程序。交付后接收缓冲区又空了,接收窗口大小又变成了8B,返回ack和接收窗口大小,然后继续传后面的数据
3.捎带确认
就是当服务器接收数据之后,要构造不带数据的ack段进行确认,还有接收窗口大小。此时正好服务器也有数据准备好了,就在发送缓冲区中,那么数据就直接放到ack段中捎带着发回给接收方了
在这个例子中是200,201,202,203,204捎带在ack段中了
这个ack段的首部字段中:
seq=200,ack=610,rwnd=6
接收方客户端就把数据拿下来,然后把发送窗口大小调整为6
那么客户端作为接收方收到数据之后,也得给服务器返回ack段进行确认和接收窗口大小进行调整。而如果此时发送方的发送缓冲区还有东西要发,那么也给捎带发到了服务器了就,就是图中的10,11,12,13,14,15
这个ack段的首部字段中:
seq=610,ack=205,rwnd=5
然后服务器把已经确认的数据弹出缓冲区,并且把发送窗口调整为5
注:并不是要接收缓冲区满了才可以交付给应用程序,只要接收缓冲区里面的数据是有序的就可以
如图所示,虽然接收缓冲区没满,但是16,17有序,那么也可以把这两个交付给应用层
什么是有序?
比如下图中,乱序到达了20,21,22,这时候不可以把这个数据交付给应用程序,因为18和19还没到,不可以称之为有序
4.超时重传
只要发送方没有在规定时间内收到服务器的ack确认段,那么时间到了以后就会进行重传,并重置定时器,直到收到了确认段
1.发送方的发送报文丢失了
定时器到时间后就会重新传
2.接收方发回来的ack段丢了
也是由发送方时间到了以后重新发送,接收方收到了重复的数据,会再次返回ack确认段
5.快重传、立即确认
推迟确认的好处:
如果两个段到来的时间间隔很短的话,就可以二合一只返回一个ack段,也就是可以累计确认
立即确认:
收到一个报文段立即返回ack确认段
1.推迟确认的缺点
推迟确认并不一定都是好的,下面这个例子体现了推迟确认的缺点
其实就是如果发的这些报文段里面有一个丢了,由于推迟确认机制,在这之后的报文段全都得重新发送
在这个例子中,第2次传的数据丢失了,如下图所示,接收缓冲区大小为4了,构造四个段
分别装着22,23,24,25,直接把四个都发送,接收方收到第一个的时候选择推迟确认0.5秒
其中23丢了,剩下3个都到达了。这是接收缓冲区大小还剩下3而不是1。接收缓冲区大小和确认号是一起看的,从确认号623开始的后面的这部分全是接收缓冲区,所以是3而不是1
所以返回的ack段的ack是623,接收窗口的值是3
发送方收到ack段,把发送窗口调整为3,。但是呢,发送方已经把23,24,25全都发了,所以现在不会再次发送23,24,25这三个数据了,而是会在这里等着他们的ack确认段发过来。但是我们知道这不会发过来,因为接收方就没收到23,不能确认23,由于累计确认,那也就没办法确认24,25。只能等23这个报文段超时,超时后会重传(23报文段超时后不久,24,25也都会超时,并且也会重传)
但其实接收方已经收到24,25报文段了,我们实际上没必要重新传。可是推迟重传导致在发送方看来接收方没收到24,25,所以24,25还会重新传一遍
2.快重传、立即确认
其实就是服务器只要收到一个段,就确认一个段
在这个例子中,第二个23丢失了。但是22到了,会返回ack=623。
24到了,会返回ack=623。25到了,会返回ack=623。
这样就有了3个确认号相同的冗余的ack,此时会立即重传ack对应的报文即623
3.易错点
第一个ack=623不是冗余ack,因为人家本来就该发
后面的624,625发过来的ack=623才是两个冗余ack
那还得有个比如626再发一个ack=623,才是三个冗余ack,才会触发重传机制
3.4 拥塞控制
TCP规定阈值不能小于2
拥塞窗口是发送端根据网络拥塞情况确定的窗口值,而不是接收端确定的。
1.慢开始、拥塞避免
横轴的单位是 RTT,比如2那就是2RTT
竖轴的单位是MSS,比如16就是 16MSS
下图有一个条件是接收窗口无限大,那么发送窗口就取决于拥塞窗口的大小了
一开始是指数级别增长,是2的指数,直到达到阈值ssthresh=16
达到阈值后,变成一次只加1
一直加1加到拥塞窗口大小为24的时候发生了超时重传,说明严重拥塞,这时候重新慢开始,直接把cwnd设为1,重新开始指数增加,只是这次也会把阈值从16调整为 超时重传是拥塞窗口的一半大小即24/2=12这么大。
然后就是一样的过程,慢开始。1+1=2,2+2=4,4+4=8,到了这时 8+8=16>12,所以12这个阈值会限制这次的窗口调整,仅会调整为 8+4=12这么大,然后开始拥塞避免算法慢慢加1
2.快重传、快恢复
在t=12RTT之前都和慢开始那边一样的,而在t=12RTT的时候发生的不是超时重传而是快重传了,即在这个时刻收到了3个重复确认,执行快重传,说明的是网络有点拥塞而不是严重拥塞
和前面的区别就是,前面会直接把拥塞窗口值调整为1MSS,而这个只是调整为发生拥塞时的值的二分之一,称为快恢复
后面就是继续使用拥塞避免算法
注:
TCP规定阈值不能小于2