第五章 传输层
在OSI七层模型中,传输层位于表示层和传输层之间。对于通信来说,传输层是最高层;对于用户来说,传输层是最底层。非主机的网络设备(如路由器、网关)通常不涉及传输层的协议和功能,通常只有主机才涉及传输层的相关协议和功能。其主要功能如下:
其主要协议有:
端口号的划分(属于约定,不具有强制力):
端口号主要按范围进行划分,大致如下:
1. 服务端使用的端口号:范围[0, 49151],具体划分如下:
1. 熟知端口号:[0, 1023],主要分配给重要重要的应用程序,常见程序分配表如下:
2. 登记端口号:[1024, 49151]
2. 客户端使用的端口号:范围[0, 65535],在客户端程序运行时动态随机分配
在程序设计时,通常用套接字绑定IP地址和端口号(套接字,socket,意译为插槽)。
UDP只是在IP数据报服务上提供了传输层的基本功能(即为进程提供socket逻辑通信,提供复用和分用),其特点为:
UDP的首部格式:
UDP首部只有8 Byte,只存了源端口、目的端口、UDP长度(为整个UDP报文长度)。源IP和目的IP在IP数据报中。UDP包可以不要数据段,长度最少为8。
当找不到目的端口时,则UDP数据报会被丢弃,并发送ICMP端口不可达差错报文。
当UDP检验和校验错误,则UDP数据报会被丢弃。
UDP在生成校验和时,会生成一个伪首部,该伪首部相似于IP数据报报头但不同于IP数据报,该伪首部只参与校验和计算,不参与传输:
校验和适用二进制反码求和再反码(会检验数据部分),具体计算规则如下:
1. 各二进制位正常求和,正常溢出
2. 若最高位产生溢出,则再原基础上再加 1
在发送时,上图UDP首部中校验和位设置为0后再计算,计算结果填充回原校验和位。
在接收时,直接进行计算,若最后计算结果全1,则校验成功。
TCP的特点主要有:
TCP报文段的结构如下:
各字段结构如下:
URG
:urgent,表示该报文要紧急传输,不用在发送缓存中排队,要配合紧急指针使用。紧急数据报不需要排队,直接交由操作系统发送。该特性并不常用,只要有一个程序使用大家都会使用,最后效果是大家都没用。另外一个原因是由于实现不同,特性可能也不同。ACK
:确认位,只有 ACK=1
时确认号才有效,才开启TCP确认机制。PSH
:push,要求接收方尽快接收该数据,不用在接收缓存中排队。RST
:复位,表示TCP中出现了严重差错(例如建立连接过程中序号计算出错),必须重新建立连接,也可以用于拒绝一个非法报文段,或拒绝打开连接。SYN
:同步位,表示是请求建立连接的报文。FIN
:finish,表示报文传输完毕,要求释放连接。URG=1
时有意义。但是序号字段也可以确定偏移量...序号
、 数据偏移
、 紧急指针
,那如何同时标记 报文中紧急数据起始地址
、 报文中普通数据起始地址
、 紧急数据偏移量4096
、 普通数据偏移量1024
数据偏移
只用4位就可以确定 报文中普通数据起始地址
,而 紧急指针
却要用16位来确定 报文中紧急数据起始地址
?序号
就可以标记紧急数据的偏移量,紧急指针是干什么的?TCP连接有如下三个阶段:
先确定几个基本设定:
TCP连接的建立
TCP连接的建立主要经过以下三个过程:
1. 客户端向服务端发送连接请求报文段,无数据荷载。各标志位参数为:
SYN = 1
,表示是连接请求报文段
序号 = x
, x
为初始序列号(ISN,客户端随机生成,预防序列号预测攻击)
ACK = 0
,字段不使能,因为客户端此时不知道服务端分配的序号。
2. TCP服务端为该连接准备分配缓存和变量,随后发送确认报文段,无数据荷载,表示允许连接。各参数标志位为:
SYN = 1
,表示为确认报文段
序号 = y
, y
为随机数(服务端随机生成)
ACK = 1
,确认位使能。
确认号 = x + 1
,确认报文段也要占用一个序号,故加一
3. 客户端收到允许连接通知,并对该通知进行确认,可以携带数据荷载并传输数据,若不携带荷载则为一个普通空包,可以当做一个 Keep Alive
信号。各标志位与再发一个"空包"意义相同,为:
SYN = 0
序号 = x + 1
ACK = 1
确认号 = y + 1
注意,HTTP协议中所使用的TCP连接在第三次握手时就会发送请求报文。
因此TCP连接的三次握手可以直接理解为一次申请、一次同意、一次TODO。
SYN泛洪攻击:
服务端在收到客户端发出的连接请求报文段(SYN=1)后服务器都需要为其进行分配资源,而TCP客户端直到收到确认报文段(SYN=1)后才会分配资源,因此利用此方式进行的攻击就叫SYN泛洪攻击。
通常使用SYN Cookie解决SYN泛洪攻击。
TCP连接的释放
在TCP标准RFC 793中,关闭TCP的意思为 "I have no more data to send."。
并且规定了以下预期效果(因为TCP是全双工通信):
1. 申请关闭的用户可以继续接收数据,直到对方也申请关闭。
2. 发送者在收到对方的关闭信号后,仍然会可靠地把缓冲区中未发送的数据可靠地传输到接收方那里。当发送者这边接收到连接断开的提示时也就意味着接受着成功的收到了发送者缓冲区中所有待发送的信息。而接受者在关闭TCP后也必须持续接收发送者缓冲区未发送完的数据。在上述要求下:
1. 发送者收到接受者的FIN报文后,会构造一个FIN报文并安排到待发送队列的末尾,并拒绝新的信息入队(并发送ACK响应该FIN报文避免重传)。(因此FIN报文通常不是紧急报文)
2. 发送者的FIN报文在自己的发送队列上发送完毕后,会等待接受者的ACK响应。若超时未响应,则会告知用户。随后回收资源。
3. 简单来说,TCP连接的释放就是允许将全双工的TCP先关闭为单工,再完全关闭。
在上述预期效果的背景下再去了解和学习四次挥手会好一些。
TCP的释放的四次挥手主要有以下四个阶段:
1. 当一方选择关闭连接时(记作A),发送连接释放报文,通常不携带数据同时停止发送数据,但是保持数据的接收(因为对方缓冲区中可能还有数据)。各标志位为:
FIN = 1
,表示是连接释放报文,又叫FIN报文。
ACK = 1
,当然需要ACK。
序号 = u
,序号该是多少就是多少。
2. 另外一方(记作B)收到连接释放报文后,发送该报文的ACK应答,避免重复发送。注意由于ACK的特殊机制,其会比B的发送缓冲区中未被发送的数据先发送。随后B将自己的FIN报文放到自己的发送队列末尾,并拒绝新报文进入队列。在进入环节3之前,FIN之前的所有未发送报文均会被正常发送(但此步骤通常不单独讨论)。该ACK帧的各标志位为:
ACK = 1
,我也不明白不需要ACK的ACK为什么要加ACK,但是ACK都要加ACK。
序号 = v
,该序号会在发送完缓冲区队列后变为 w - 1
。
确认号 = u + 1
,确认号正常计算。
3. FIN帧在B的队列中到达队头,FIN帧从B中发送。各标志位为:
FIN = 1
。
ACK = 1
,需要应答。
序号 = w
,序号正常计算。
确认号 = q + 1
,确认号正常计算。
4. A应答B的FIN帧。各标志位为:
ACK = 1
。
序号 = u + 1
,序号正常计算。
确认号 = w + 1
,确认号正常计算。
最后申请关闭连接的A要等待两个最长报文段确保最后一个ACK正确送达(无论发什么报文都要等待两个最长报文段,超时则重传)。
四次挥手中,其中有两次都是ACK应答。而ACK应答无论发送什么报文都要ACK,实际上关键挥手共计两次。
可靠传输:
可靠传输要求接收方接收到的字节流与发送方发出的字节流完全一致。
TCP实现可靠传输的机制主要有:
冗余ACK机制:
每当一个比期望序号大的失序报文段到达,接收方都会发送一个冗余ACK来表示其期待的下一顺序字节。
该机制有助于催促发送方快速重传。
TCP实现流量控制使用滑动窗口机制实现,具体方法为: