运输层 ######################################## 运输层是通信子网和资源子网的分界线,但其并不是通信子网和资源子网的一部分。运输层协议为 ``进程`` 之间提供了逻辑通信(即 ``端到端通信`` ),而网络层提供的是 ``主机`` 之间的逻辑通信(即 ``点到点通信`` )。 运输层提供的功能有: - 进程之间的逻辑通信 - 通过套接字实现复用和分用 - 对收到的报文(首部和数据部分)进行差错校验 - 提供面向连接的、可靠的 TCP 和 无连接的、不可靠的 UDP 服务 .. important:: 只有主机之间的通信才用到运输层协议,而转发网络(路由器和交换机)只需要用到下三层协议 运输层通过套接字来区分不同主机上的应用进程,通过端口号来区分同一主机上的不同应用进程。端口号长达 16 bit,其将主机上的端口划分如下: +------------------+-------------+------------+ | 服务端用的端口号 | 熟知端口号 | 0~1023 | | +-------------+------------+ | | 登记端口号 | 1024~49151 | +------------------+-------------+------------+ | 客户端用的端口号 | 49152~65535 | +------------------+-------------+------------+ .. hint:: 客户端使用的端口号又被称为 ``临时端口`` 这是因为这些端口号在客户端使用时动态地选择,使用后又立即销毁 常用的应用端口为: +------------+--------+--------+------+-----+------+------+------+ | 应用程序 | FTP | Telnet | SMTP | DNS | TFTP | HTTP | SNMP | +------------+--------+--------+------+-----+------+------+------+ | 熟知端口号 | 20, 21 | 23 | 25 | 53 | 69 | 80 | 161 | +------------+--------+--------+------+-----+------+------+------+ UDP **************************************** UDP 是无连接、不可靠的协议,其在 IP 之上只提供两个附加服务:多路复用和差错校验。UDP 适用于实时性强、不要求数据完整性、或者传输数据量少的情况。比如: TFTP, DNS, SNMP, RTP UDP 具有以下优点: - 无需建立连接 - 无连接,无需维护连接状态 - 分组首部开销小(只有 8B ) - 没有拥塞控制,网络中的拥塞不会影响主机的发送效率 .. important:: UDP 是面向报文的,报文是 UDP 处理的最小单位。其对应用层交付的报文既不分割也不合并,在加入首部后就直接交付给 IP 层 UDP 首部为: +---------------+-----------------+ | 16 位源端口号 | 16位目的端口号 | +---------------+-----------------+ | 16位 UDP 长度 | 16位 UDP 校验和 | +---------------+-----------------+ | 数据(若有) | +---------------+-----------------+ - UDP 长度字段代表 ``首部 + 数据`` 的总长度 若 UDP 发现报文中的目的端口号不正确,则直接丢弃该报文,并发送 ``ICMP :目标不可达`` 差错报文 .. important:: UDP 校验和有两种特殊情况: - 若校验和字段全为 0 ,说明发送方不使用校验和校验数据 - 若校验和字段全为 1 ,说明校验和实际上是全为 0 若校验失败,则可以丢弃报文或者是交付给上层,同时附加上错误报告 TCP **************************************** TCP 的主要特点如下: - 面向连接 - 只能点对点通信,无广播能力 - 保证交付的数据无差错、不丢失、有序 - 提供全双工通信,通信两端可以在任意时刻、同时发送数据 - 面向字节流 - TCP 的首部长度为 20B ~ 60B TCP报文段结构: .. image:: assets/TCP报文段结构.png 连接管理 ======================================== TCP 连接的建立采用 C/S 方式,发起连接的进程为客户机,等待被连接的进程为服务器。而连接的拆除可以由任意一方发起。 - TCP 连接的建立:三次握手 1. 客户机向服务器发送 TCP 报文段:( SYN = 1, seq = x ) 2. 服务器发送确认报文并分配资源:( SYN = 1, ACK = 1, seq = y, ack = x + 1 ) 3. 客户端发送确认报文并分配资源:( SYN = 1, seq = x + 1, ack = y + 1 ) .. hint:: 由于服务器的资源只在第二步分配的,而客户机的资源实在第三步分配的,这就导致服务器很容易受到 SYN 泛洪攻击 - TCP 的拆除:四次挥手 TCP 连接的拆除可以由连接双方的任意一方发起,此处以客户机发起为例: 1. 客户机发送释放报文段:( FIN = 1, seq = u ) 。此处 u 为前面已发送的数据的最后一个字节的序号 + 1 2. 服务器发送确认报文:( ACK = 1, seq = v, ack = u + 1 ) 3. 服务器发送释放报文:( FIN = 1, ACK = 1, seq = w, ack = u + 1 )。此处 w 为前面已接收的数据的最后一个字节的序号 4. 客户机发送确认报文:( ACK = 1, seq = u + 1, ack = w + 1 ) .. important:: - 若连接一方发送了释放报文,这意味着它这一端不能再发送数据,但是另外一端依然可以发送数据。 - 即使一端发送了释放报文,另外一端在存在数据的情况下依然可以继续发送数据。 可靠数据传输 ======================================== 为了保证数据的按序交付,TCP 使用了校验、序号、确认和重传等机制。 TCP 的数据校验机制与 UDP 完全一致。 1. 序号: TCP 为发送的 ``字节`` 编号,在其报文首部的序号字段填入本报文段所发送的第一个字节的编号 2. 确认: TCP 首部的确认号字段是期望对方发送的下一个报文段的数据的第一个字节的编号。一般来说是字节流缺失的第一个字节。 TCP 使用累计确认,其只发送字节流中第一个缺失的字节。 3. 重传: - 若在 ``报文段`` 的计时器结束之后还没有收到确认字段,则重传 - 若收到 3 个相同的 ACK ,则重传(冗余 ACK 技术) 流量控制 ======================================== TCP 的流量控制主要用于保证发送端的发送速度和接收端的接收速度相匹配,以防止接收端处理速度跟不上。其依赖于 ``滑动窗口协议`` : 1. 发送端根据当前网络拥塞程度确定自己的窗口值,称为拥塞窗口( cwnd ) 2. 接收端根据自己剩余缓存的大小,动态调整发送窗口的大小,称为发送窗口( rwnd ),该窗口值将会被附加到首部发送给发送端。 3. 发送端取 min(cwnd, rwnd) 作为自己的发送速率。 拥塞控制 ======================================== 拥塞控制主要用于保证网络能够承受现有的网络负荷,其受制于当前网络下的所有主机、交换机、路由器等。为了防止拥塞,因特网使用以下四种算法:慢启动、拥塞避免、快速重传、快速恢复,其一般被概括为:加性增,乘性减。 - 慢启动:TCP 启动时 cwnd 设置为一个 MSS,其后每 ``首次到一个报文的 ACK`` 便将 cwnd 加一。使得发送速率以较低速度启动,但是以指数倍增。 当 1. 检测到超时产生的丢包事件后:ssthresh = cwnd/2, cwnd = 1 2. 当 cwnd = ssthresh 时:进入拥塞避免模式 3. 当检测到 3 个冗余 ACK 时:执行快速重传和快速恢复 - 拥塞避免:在进入拥塞避免状态后:每经过一个 RTT 将 cwnd + 1, 而不是每收到一个 ACK 就加一,使得 cwnd 从指数增长进入线性增长。 - 快速重传和快速恢复:当收到三个冗余 ACK 后,``立即`` 重传丢失的报文而不等待计时器超时、执行 ssthresh = cwnd = cwnd/2 而不是令 cwnd = 1 滑动窗口协议 **************************************** 信道效率:发送方将字节推到信道所用的时间与发送时间整个发送周期所用时间的比值 停等协议 ======================================== 对于停等协议而言,其动作如下: - 发送方发送一个分组并等待 ACK, 超时重传。 - 发送的分组使用 {0, 1} 对分组进行编号,若接收方接收到序号相同的分组,则丢弃。 停等协议相当于发送窗口和接收窗口均为 1 的滑动窗口。 GBN ======================================== 回退 N 步( :abbr:`GBN (Go Back N)` )动作如下: - 若接收方接受到有序分组则发送 ACK 进行确认,否则直接丢弃分组。 - GBN 使用 ``累计确认`` 。 - 发送方向接收方以流水线形式连续发送多个分组,分组的数量收发送窗口的大小制约 - 若发送方等待 ACK 超时,则重传超时分组以及之后的所有分组 GBN 相当于发送窗口为 n , 接受窗口为 1 的滑动窗口。 若采用 n bit 进行编号,则发送窗口的大小 :math:`W_t` 应当满足: :math:`1\leq W_t\leq 2^n-1` .. hint:: 当 :math:`W_t = 2^n-1` 会如何呢? 这里设使用 3 bit 进行编号,设 :math:`W_t = 2^n = 8` 。在发送端发送了 0~7 号共 8 个分组后,有两种情况: #. 所有分组都得到了确认,这时发送端会发送一组新的分组,序号循环使用,依然为 0~7 #. 分组全部丢失,这时发送端要重新发送之前的分组,序号依然是 0~7 那么在两种情况下,接收端将无法判断新到达的分组是新分组还是重发的分组。 SR ======================================== 选择重传( :abbr:`SR (Select Retransmission)` )。相比 GBN 而言,当分组丢失、失序的时候,将失序的分组进行缓存而不是直接丢弃,其缓存大小受接受窗口限制。 SR 具有以下特点: #. 接收方不再使用累计确认,对于接收到的、序号位于当前窗口之内和当前窗口之前的分组都发送 ACK 确认 #. 发送方发送的所有分组都需要被确认,否则超时重传 若采用 n bit 进行编号,则发送窗口 :math:`W_T` 和接受窗口 :math:`W_R` 应满足 :math:`W_R + W_T \leq 2^n` 。其中 :math:`W_R\leq \frac{1}{2} 2^n` .. seealso:: - `TCP协议详解 `_ 套接字 API 与 TCP 之间的关系 **************************************** [#socket]_ .. image:: assets/2021-08-31-00-36-08.png .. [#socket] `下面有关tcp连接握手,说法错误的是 `_