文章目录
-
- 摘要
- 为什么需要运输层?
- 用户数据报协议UDP
-
- UDP首部
- 传输控制协议TCP
-
- 停止等待协议
-
- 这里先讲一下停止等待协议:
- 确认丢失和确认迟到:
- 滑动窗口
-
- 流量控制
- 拥塞控制
-
- 探测网络拥塞情况
- 超时 == 拥塞?
- 三次握手与四次挥手
-
- 重要字段
- 三次握手
- 四次挥手
-
- 为什么握手只要三次,挥手要四次?
- 为何建立连接时一起传输,释放连接时却要分开传输?
- 为什么客户端在TIME-WAIT阶段要等2MSL?
摘要
运输层是整个网络体系结构中的关键层次之一,本篇主要围绕以下几个主题展开:
1、运输层的作用
2、UDP
3、TCP
4、在不可靠的网络上实现可靠传输的工作原理
5、TCP滑动窗口、流量控制、拥塞控制和连接管理
前情提要:
我问你这篇保熟不?! – 做服务端开发,不懂网络层,真的可以吗?
为什么需要运输层?
运输层向它上面的应用层提供通信服务,属于面向通信部分的最高层,同时也是用户功能中的最底层。
看图说话:
从IP层来说,通信的两端是两台主机。严格地讲,两台主机进行通信就是两台主机中的应用进程互相通信。
从运输层的角度看,通信的真正端点并不是主机而是主机中的进程。
可以看到,每台主机中都有不少于一个的进程,主机A中的AP1、AP2要和主机B中的AP3、AP4进行通信,却共用一个传输层,这说明传输层有很重要的功能:复用&分用。
复用是指在发送方不同的应用进程都可以使用同一个运输层协议传送数据。
分用时指接收方的运输层在去掉报文的首部后能够把这些数据正确交付目的应用进程。
总结一下:网络层为主机之间提供逻辑通信,运输层为应用进程之间提供端到端的逻辑通信。
此外,运输层还向高层用户屏蔽了下面网络核心的细节。
用户数据报协议UDP
用户数据报协议UDP只在IP的数据服务之上增加了很少一点功能,这就是复用和分用的功能以及差错检测功能。
代码语言:javascript复制1.UDP是无连接的。
2.UDP不保证可靠交付。
3.UDP是面向报文的,发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。
应用层交给UDP多长的报文,UDP就发送多少,因此应用程序必须选择长度合适的报文,
若报文太长,UDP把它交给IP层后,IP层传送时可能要进行分片,降低IP层效率。
4.UDP没有拥塞控制。
5.UDP首部开销很小,只有8个字节。
6.UDP支持一对一、一对多、多对一、多对多的交互通信。
所以,UDP将速度点满,但是稳定性就比较缺乏了。
UDP首部
伪首部仅仅是为了计算检验和。
(好可怜)
如果接收方UDP发现端口号不正确,就丢弃该报文,并由网际控制协议ICMP发送“端口不可达”差错报文给发送方。
传输控制协议TCP
代码语言:javascript复制TCP 是面向连接的运输层协议.
每一条 TCP 连接只能由两个端点(endpoint), 每一条 TCP 连接只能是点对点的.
TCP 提供可靠交付的服务. 通过 TCP 连接传送的数据, 无差错, 不丢失, 不重复, 并且能够按序到达.
TCP 提供全双工通信. TCP 连接的两端都设有发送缓存和接收缓存, 用来临时存放双向通信的数据.
面向字节流. TCP 中的流(stream)指的是流入到进程或从进程流出的字节序列.
TCP的连接是逻辑连接,虚拟连接,不是物理连接。
TCP 连接的端点叫做套接字 (socket),套接字=IP:port。
停止等待协议
其实这点已经是初见端倪了。前面说,UDP以稳定性换速度,那么TCP作为另一个传输协议,很自然的能想到其为稳定性放弃了一定的速度。
理想的传输有以下两个特点:
1、传输信道不产生差错
2、不管发送方以多块的速度发送数据,接收方总来得及处理收到的数据
很显然,目前不现实。
这里先讲一下停止等待协议:
每发完一个分组就停下来等待对方的确认,收到确认后再发送下一个分组。
接收端接收分组检测出现了差错, 就丢弃分组, 其它什么也不做.。发送端超过了一段时间没有收到确认信息, 即认为发送的分组丢失了, 因而重传前面发送过的分组, 叫超时重传。
所以,发送端必须暂时保留已发送的分组的副本, 只有收到相应的确认后才能清除保留的分组副本; 分组和确认分组必须进行编号, 这样才能明确是哪一个发送出去的分组收到了确认, 而哪一个分组还没有收到确认; 超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些(网络时延)。
这里面细节很多,会引出很多东西。
确认丢失和确认迟到:
确认丢失: 接收端发送的确认丢失了。 这时发送端需要重传数据分组, 接收端又会收到这个分组, 接收端应该丢弃这个重复的分组, 并再次向发送端发送确认, 不能认为发送过确认就不再发送确认.
确认迟到: 接收端发送的确认迟到了, 接收端会收到重复的确认, 然后丢弃重复的确认. 接收端收到重复的分组, 丢弃重复的分组, 并重传确认分组.
利用确认和重传机制, 可以在不可靠的传输网络上实现可靠的通信, 上面这种可靠传输称为自动重传请求 ARQ(Automatic Repeat Request)
概念讲的差不多了,该上算法了。
滑动窗口
TCP 的滑动窗口是以字节为单位的。
现假定 A 收到了 B 发来的确认报文段,其中窗口是 20 字节,而确认号是 31(这表明 B 期望收到的下一个序号是 31,而序号 30 为止的数据已经收到了)。
在没有收到B的确认的情况下,A可以连续把窗口内的数据都发送出去,凡是已经发送过的数据,在未收到确认前都必须暂时保留,以便在超时重传的时候使用。
显然,窗口越大,发送方就可以在收到对方确认之前连续发送更多的数据,因而可能获得更高的传输效率。
此外,发送方的窗口一定不能大于接收方的窗口大小,发送方的窗口大小还要受到当时网络拥塞程度的制约。
流量控制
如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。
利用滑动窗口机制可以很方便地在TCP连接上实现对发送方的流量控制。
设A向B发送数据。在连接建立时,B告诉了A:“我的接收窗口是rwnd = 400”(这里的rwnd表示receiver window)。因此,发送方的发送窗口不能超过接收方给出的接收窗口的数值。
拥塞控制
拥塞控制与网络的拥堵情况相关联,而流量控制与接收方的缓存状态相关联。
了解TCP三次握手的朋友都知道,两台主机在传输数据包的时候,如果发送方迟迟没有收到接收方反馈的ACK,那么发送方就会认为它发送的数据包丢失了,进而会重新传输这个丢失的数据包。
然而实际情况有可能此时有太多主机正在使用信道资源,导致网络拥塞了,发送的数据包被堵在了半路,迟迟没有到达。这个时候发送方误认为是发生了丢包情况,会重新传输这个数据包。
结果就是不仅浪费了信道资源,还会使网络更加拥塞。因此,我们需要进行拥塞控制。
探测网络拥塞情况
无论如何,在探测的过程中都会出现瓶颈,或者说,类似于天花板了。
为了平衡各方面效率,使用以下方式:
前期指数增长,到达阈值之后,就以一个一个线性的速度来增长。我们也把指数增长阶段称之为慢启动,线性增长阶段称之为拥塞避免。
超时 == 拥塞?
有可能是因为某个数据包出现了丢失或者损害了,导致了这个数据包超时事件发生了
为了防止这种情况,我们是通过冗余 ACK来处理的。我们都知道,数据包是有序号的,如果A给B发送M1, M2, M3, M4, M5…N个数据包,如果B收到了M1, M2, M4…却始终没有收到M3,这个时候就会重复确认M2,意在告诉A,M3还没收到,可能是丢失
我们也把这种情况称之为快速恢复。
三次握手与四次挥手
重要字段
先别管啥握手挥手的,这几个字段先背一下。
代码语言:javascript复制1)序号(sequence number):Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
2)确认号(acknowledgement number):Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq 1。
3)标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN等。具体含义如下:
URG:紧急指针(urgent pointer)有效。
ACK:确认序号有效。(这个)
PSH:接收方应该尽快将这个报文交给应用层。
RST:重置连接。
SYN:发起一个新连接。(这个)
FIN:释放一个连接。(这个)
三次握手
所谓的三次握手即TCP连接的建立。这个连接必须是一方主动打开,另一方被动打开的。以下为客户端主动发起连接的图解:
四次挥手
为什么握手只要三次,挥手要四次?
TCP释放连接时之所以需要“四次挥手”,是因为FIN释放连接报文与ACK确认接收报文是分别由第二次和第三次"握手"传输的。
为何建立连接时一起传输,释放连接时却要分开传输?
建立连接时,被动方服务器端结束CLOSED阶段进入“握手”阶段并不需要任何准备,可以直接返回SYN和ACK报文,开始建立连接。释放连接时,被动方服务器,突然收到主动方客户端释放连接的请求时并不能立即释放连接,因为还有必要的数据需要处理,所以服务器先返回ACK确认收到报文,经过CLOSE-WAIT阶段准备好释放连接之后,才能返回FIN释放连接报文。
为什么客户端在TIME-WAIT阶段要等2MSL?
为的是确认服务器端是否收到客户端发出的ACK确认报文
当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的计时器。MSL指的是Maximum Segment Lifetime:一段TCP报文在传输过程中的最大生命周期。2MSL即是服务器端发出为FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。
服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文;
如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时;否则客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。
所以,客户端要经历时长为2SML的TIME-WAIT阶段;这也是为什么客户端比服务器端晚进入CLOSED阶段的原因。