传输层
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,例如电话会议直播等