传输层
0x00 基本概念
传输层的基本功能
- 提供进程之间的逻辑通信
- 对收到的报文进行差错检测(首部和数据部分)
- 复用和分用:复用指的是发送方不同的应用进程都可以使用同一个传输层协议,分用是接收方的传输层在剥去报文的首部后能够把这些数据交付给目的应用进程
端口用来标识主机中的应用进程,传输层的服务访问结点(SAP)为端口,端口号只具有本地意义。端口号长度为 16 位,因此其能表示 个端口。
注:数据链路层的 SAP 为 MAC 地址,网络层的 SAP 为 IP 地址
端口号的划分:
- 服务端使用端口号
- 熟知端口号:0-1023,例如 FTP-21,TELNET-23,DNS-53
- 登记端口号:1024-49151
- 客户端使用端口号:49152-65535,也即短暂端口号或临时端口号,客户进程运行时动态选择
套接字:在网络中发送盒和接收方使用套接字来识别端点。
0x01 TCP
TCP 提供面向连接的服务,传输数据之前首先建立连接,传送完成之后释放连接,TCP 不提供广播和组播服务,且提供流量控制和拥塞控制功能,保证数据可靠且无差错、不丢失、不重复、顺序地交付,因为其提供面向连接的可靠服务,所以不可避免地增大了许多开销。使用场合有:FTP, HTTP, TELNET。一个 TCP 报文的首部长度为 20B。
每一条 TCP 连接只能是点对点的,TCP 连接只能由 2 个端点。提供全双工通信,为此 TCP 连接的两端都具有发送缓存和接受缓存,发送缓存存储:
- 准备发送的数据
- 已发送但未收到确认的数据
接收缓存存储:
- 已到达但尚未被应用程序读取的数据
- 未按序到达的数据
TCP 报文段:
-
序号字段:占 4 字节,表示发送的报文段中数据部分第一个字节在本地发送缓冲区中的编号
-
确认号字段:占 4 字节,若确认号为 N,则表示 N 之前到 N-1 为止的所有数据都已正确收到,其表示期望下次收到来自对方报文段的第一个字节的编号
-
数据偏移字段:占 4 位,即首部长度,以 4 字节(32 位)为基本单位,因此当这个字段的值为 15 时,TCP 的首部长度达到最大值即为 60 字节
-
窗口字段:占 2 字节,用于告知对方自己所能接受的数据的大小,单位是字节
即接收端窗口
rwnd的大小 -
推送位 PSH:如果 PSH=1 则应尽快交付应用程序而不是等缓存填满了再上交
-
复位位 RST:当 RST=1 时,表明 TCP 连接已经出现了严重差错,必须释放连接然后重新建立连接
-
检验和:占 2 字节,检验的范围包括首部和数据部分,需加上 12 字节的伪首部
TCP 报文段作为 IP 数据报的数据部分封装在 IP 数据报中,TCP 报文段既可以用来运载数据也可以用来建立、释放连接和应答
TCP 首部的长度必需是 4 字节的整数倍
TCP 连接管理:
- TCP 连接的建立(三次握手):
- 客户机向服务器发送一个连接请求报文段,此报文段不含应用层数据,SYN=1,客户端会选择一个随机的起始序号
seq=x - 服务端收到并同意后,发回确认,分配 TCP 缓存和变量,SYN=1, ACK=1,确认号为 x+1,服务器随机产生起始需要
seq=y,同样不包含应用层数据 - 客户端收到后,向服务器发回确认,分配 TCP 缓存和变量,ACK=1,序号为 x+1,确认号 ack 字段为 y+1,该报文段可携带数据
- 客户机向服务器发送一个连接请求报文段,此报文段不含应用层数据,SYN=1,客户端会选择一个随机的起始序号
- TCP 连接的释放(四次挥手):
- 客户机发送连接释放报文段,FIN=1,
seq=u,TCP 是全双工的,当发送 FIN 报文时,发送的那一端就不能再发送数据了,而接收的那一段此时仍可以发送数据 - 服务端发送确认,确认号为 u+1,此时 TCP 连接处于半关闭状态,服务端发送数据,客户端仍要接收
- 若服务器已经没有向客户端发送的数据,那就通知 TCP 释放连接,此时发送 FIN=1 的连接释放报文段
- 客户端收到连接释放报文段之后,必需发送确认,ACK=1,
seq=u+1,此时 TCP 连接没有被释放掉,等待 2MSL 后客户端关闭连接
- 客户机发送连接释放报文段,FIN=1,
TCP 连接的端口为套接字,主动发起连接的为客户机,被动等待连接的为服务器
MSL 为最长报文段寿命,一般为 2 分钟
TCP 的重传:
- 超时重传:TCP 使用自适应算法,记录一个报文段发出的时间以及相应收到确认的时间,两个时间相差即为往返时间(RTT),TCP 会保留一个加权平均往返时间,超时重传时间(RTO)应略大于加权平均往返时间。
- 冗余 ACK:TCP 规定每当有比期望序号值大的失序报文到达时,发送一个冗余 ACK,指明下一个期待字节的序号,当发送方收到对同一报文段的 3 次冗余 ACK 之后就认为此报文段已经丢失
TCP 的流量控制是基于滑动窗口的,而且窗口大小可以动态变化的(区别于数据链路层的滑动窗口),发送窗口的大小取接收窗口rwnd和拥塞窗口cwnd的最小值
发送窗口的单位是字节数,比如发送窗口值为 2000,意思为发送端在收到一个确认之前最多还可以发送 2000 字节
TCP 的拥塞控制目的是为了让网络能够承受现有的网络符合,一般采用如下几种算法进行拥塞控制:
-
慢开始算法:连接好之后开始发送 TCP 报文段,先令
cwnd=1(即 1 个最大报文段的长度 MSS),每经过一个传输轮次(即一个往返时延 RTT),拥塞窗口cwnd就开始加倍,当其增大到一个规定的阈值ssthresh之后,改用拥塞避免算法 -
拥塞避免算法:发送端的拥塞窗口
cwnd每经过一个 RTT 就增加一个 MSS 的大小,使其加法增大,每当出现一次超时时,令慢开始门限 **ssthresh等于当前cwnd的一半 **,即乘法减小,然后比较cwnd和ssthresh的大小:- 当
cwnd < ssthresh时,使用慢开始算法 - 当
cwnd > ssthresh时,使用拥塞避免算法 - 当
cwnd = ssthresh时,通常使用拥塞避免算法,也可以使用慢开始算法
- 当
-
拥塞处理算法:只要检测到拥塞,就把
ssthresh设置为cwnd的一半,然后把cwnd重新设置为 1,重新开始慢开始算法
好好体会上图的过程
并且要注意发送窗口的取值为拥塞窗口和接收窗口的最小值
拥塞窗口是由发送端根据网络拥塞情况确定的窗口值,初始的拥塞窗口的大小为最大报文段的长度。
如果当前
cwnd为 4 而ssthresh为 6,那么从 4 的下一个即为 6(直接上升到门限值),然后开始往后为加法增大 -
快重传:如果收到三个重复的 ACK 报文,不必等到重传计时器超时就重传对方未收到的报文段
-
快恢复:当收到三个重复的 ACK 报文时,然后将
ssthresh设置为cwnd的一半,然后将cwnd设置为改变后的ssthresh的值,然后执行加法增大的拥塞避免算法
0x02 UDP
UDP 是一个无连接的非可靠传输协议,其在 IP 之上仅附加 2 个服务:多路复用和对数据的错误检查,其执行速度快且实时性较好,一般用于 TFTP, DNS, SNMP, RTP。UDP 首部大小为 8B。
TFTP 指的是小文本传送协议,RTP 为实时协议
UDP 是面向报文的,添加首部后就直接交给 IP 层,既不合并也不拆分,报文不可分割,一次交付一个完整的报文,报文是 UDP 数据报处理的最小单位。
首部字段:
- 源端口:可以全为 0
- 目的端口
- 长度:最小值为 8(仅有首部的时候),包括首部和数据报的长度
- 校验和:用来检错,有错就丢弃,丢弃后发送 ICMP 端口不可达差错报文,校验和用来校验首部和数据部分,该字段是可选的,在计算校验和时,要对 UDP 数据报添加 20 个字节的伪首部,这个伪首部仅用来计算校验和,不向下传送也不向上递交,如果不使用校验和,则将校验和字段全部置为 0,如果校验和的结果恰好全为 0 则将校验和字段全部置为 1,算法为二进制反码运算求和再取反。
伪首部的内容主要包括:- 源 IP 地址
- 目的 IP 地址
- UDP 长度
0x03 TCP 和 UDP 的比较
| TCP | UDP | |
|---|---|---|
| 首部大小 | 20 字节 | 8 字节 |
| 流量控制 | 有 | 无 |
| 拥塞控制 | 有 | 无 |
| 可靠保证 | 可靠 | 应用层承担 |
| 面向 | 字节流 | 报文 |
| 伪首部大小 | 12 字节 | 20 字节 |
UDP 没有拥塞控制,因此网络拥塞也不会影响 UDP 的发送效率,某些应用中要求数据以稳定的速度发送,可以容忍一些数据的丢失,所以适合选择 UDP,例如电话会议直播等



