- 本文主要介绍传输层的两个协议TCP和UDP,也介绍了TCP的可靠传输(超时重传)、流量控制(点到点)、拥塞控制 (共同维护)、连接管理(建立连接、释放连接)四个方面技术。
#传输层的两个主要协议
TCP(Transmission Control Protocol)传输控制协议(不丢包)
UDP(User Datagram Protocol)用户数据报协议(丢包,实时(时间同步))
#UDP协议
数据格式
UDP是无连接的,减少了建立和释放连接的开销
UDP尽最大的能力交付,不保证可靠交付,因此不需要维护一些复杂的数据,首部只有8个字节(TCP首部至少需要20 字节)
UDP格式(首部 + 数据)
注:
- 其中UDP的长度为16位,为: 首部的长度 + 数据的长度
- UDP的数据长度字段是冗余的,因为完全可以通过IP数据包的首部长度和总长度计算出来传输层的数据长度。
- 传输层的数据长度 = 网络层的总长度 - 网络层的首部长度 - 传输层的首部长度
检验和(Checksum)
- 检验和的计算内容:伪首部 + 首部 + 数据
- 伪首部:占12字节
- 伪首部: 仅在计算首部检验和的时候起作用, 并不会将伪首部传递分网络层。(增强检验功能)
相关补充 - 常用命令、端口(Port)
UDP首部中端口是占用2字节,端口的取值范围: 0-65535
在请求的过程中客户发送数据的端口是随机开启的端口。
可以通过防火墙设置开启或关闭某些端口来提高安全性。(例如:服务器关闭Mysql数据库3306端口, 不允许外部访问。)
常用端口:
netstat –an
:查看被占用的端口netstat –anb
:查看被占用的端口、占用端口的应用程序telnet 主机 端口
:查看是否可以访问主机的某个端口安装telnet:控制面板 – 程序 – 启用或关闭Windows功能 – 勾选“Telnet Client” – 确定
#TCP协议
TCP协议 - 数据格式、检验和、标志位(Flags)
数据偏移(数据的偏移值或者是首部长度)
- 占四位,取值范围是0x0101- 0x1111(5 - 15)
- 乘以4:首部长度(Header Length)
- 首部长度范围: 20到60字节
检验和(Checksum)
- 同UDP一样,仅在计算首部检验和的时候起作用, 并不会将伪首部传递分网络层
- 同UDP一样,仅在计算首部检验和的时候起作用, 并不会将伪首部传递分网络层
标志位(Flags)
- URG(Urgent)
- 当URG为1的时候,紧急指针数值有效.表明当前报文段中有紧急数据,应优先传送
- ACK(Acknowledgment)
- 当ACK为1 ,确认号字段才有效.
- RST(Reset)
- 当RST=1时, 表明连接中出现严重差错,应释放连接,然后再重新建立连接.
- SYN(Synchronization)(同步)
- 当SYN为1,ACK为0表明是建立连接请求
- 同意建立连接的回复,回复为SYN为1,ACK为1
- 对连接的回应时,回复为SYN为0,ACK为1
- FIN (Finish)
- 表明数据释放完毕,要求释放连接
- PSH(Push)
- URG(Urgent)
保留
- 占6位,目前全为0
补充小细节
- 有些资料保留位(Reserved)是3位,标志位是6位,由于前3位标志位是不用的,所以两种说法都没问题,并且wireshark就是这样的
- 有些资料保留位(Reserved)是3位,标志位是6位,由于前3位标志位是不用的,所以两种说法都没问题,并且wireshark就是这样的
TCP的几个要点
- 可靠传输 (超时重传)
- 流量控制(点到点)
- 拥塞控制 (共同维护)
- 连接管理(建立连接、释放连接)
TCP - 序号、确认号、窗口
- 序号(Sequence Number)
- 占四个字节
- 在传输过程中的每一个字节(段)都有一个编号
- 建立连接之后,这个编号代表这一次TCP数据部分的第一个字节的编号
- 确认号
- 占四个字节
- 在建立连接之后,确认号代表,期望对方下一次传来的TCP数据部分的第一个字节编号
- 窗口(Window)
- 占两个字节(具体需要乘以窗口缩放系数)
- 这个字段具有流量控制功能, 用以告诉下一次发送语序的而数据大小(单位为字节)
- 序号(Sequence Number)
TCP可靠传输 - 停止等待ARQ协议
ARQ(Auto Repeat-reQuest), 自动重传请求(超时重传)
连续ARP协议 + 滑动窗口协议(提高效率)
- 发送方的窗口大小是由接受方的窗口的缓存大小决定的
- 发送方的窗口大小是由接受方的窗口的缓存大小决定的
TCP可靠传输 - SACK(选择性确认技术 )
背景
- 在传输过程中,若发送的序列中间某个数据包丢失(1,2,3,4,5其中3丢失了)TCP会通过重传最后确认的分组后续的分组(若最后确认的是2,会重传3、4、5)
- 这样原先已经正确传输的分组也可能重复发送(比如4、5),降低了传输性能
选择性确认技术
- 告诉发送方哪些数据丢失,哪些数据已经提前收到
- 使TCP只重新发送丢失的包(比如3),不用发送后续所有的分组(比如4、5)
SACK信息会放在TCP首部的选项部分(当Kind=5,代表这是SACK选项)
- Kind:占1字节。值为5代表这是SACK选项
- Length:占1字节。表明SACK选项一共占用多少字节
- Left Edge:占4字节,左边界
- Right Edge:占4字节,右边界
- (左边界301 - 右边界401的范围就代表301 - 400)
返回确认的过程中,会告诉窗口缓存大小
- 一对边界信息需要占用8字节,由于TCP首部的选项部分最多40字节,所以
- SACK选项最多携带4组边界信息
- SACK选项的最大占用字节数 = 4 * 8 + 2 = 34
- 一对边界信息需要占用8字节,由于TCP首部的选项部分最多40字节,所以
相关补充
- 一个包多次重传失败
- 不会一直重传知道成功为止,这个取决于操作系统的设置(有些系统,重传5次未成功(未收到确认报文)就会发送reset报文(RST)断开TCP连接,然后重新建立连接。
- 不足接收窗口大小
- 接收方会等待一定时间后没有后续包,就会返回确人接收到的包
- 在传输层分片(而不是在网络层)
- 提高传输的性能(可以(在传输层)发送指定分片丢失的包)
- 可靠传输是在传输层中进行控制的,如果不分段,一旦出现数据丢失,整个传输层数据都得重传(SACK)
- 需要明确的是可靠传输是在传输层进行控制。
- 一个包多次重传失败
TCP - 流量控制(端到端)
背景
- 接受方的缓存区大小是有限的(灵活调整的),发送方还发送数据,那么接受方就丢掉数据,这样会造成网络堵塞,所以需要流量控制(控制发送速率)。
原理
- 通过确认报文中的窗口字段来控制发送方的发送速率
- 发送方发送的额窗口大小不能大于接受方给出的窗口大小(接受窗口大小为0,发送方就会停止发送数据)
特殊情况
- 一开始,接受方给发送方发送的窗口为0的报文段,但是后面又有了一些空间,但是给发送方发送的非0窗口的确认报文段丢失了,于是双方陷入僵局。
- 解决方案
- 发送方接受到0窗口大小的报文就会停止发送报文,并且会开启一个计时器,隔一段时间发送一个测试报文询问接受方 最新窗口大小,窗口大小为0就会继续开启计时器。
- 发送方接受到0窗口大小的报文就会停止发送报文,并且会开启一个计时器,隔一段时间发送一个测试报文询问接受方 最新窗口大小,窗口大小为0就会继续开启计时器。
TCP - 拥塞控制
简介
- 背景:
- 拥塞控制是为了防止过多的数据注入网络,从而避免网络中的路由器或链路过载,产生的,拥塞控制是全局性的,涉及降低网络传输性能有关的所有因素。
- 拥塞控制是为了防止过多的数据注入网络,从而避免网络中的路由器或链路过载,产生的,拥塞控制是全局性的,涉及降低网络传输性能有关的所有因素。
- 背景:
TCP - 拥塞控制的方法
慢开始(slow start,慢启动)
拥塞避免(congestion avoidance)
快速重传(fast retransmit)
快速恢复(fast recovery)
MSS(Maximum Segment Size):每个段最大的数据部分大小(在建立连接时确定)(理论值)MTU一般是(1500) - 20 - 20 = 1460
cwnd(congestion window):拥塞窗口
rwnd(receive window):接收窗口(可发送所有数据的大小)
swnd(send window):发送窗口
swnd = min(cwnd, rwnd)
TCP -【拥塞控制】- 慢开始(slow start)
TCP -【拥塞控制】- 拥塞避免(congestion avoidance)
- ssthresh (slow start threshold):慢开始阈值,cwnd达到阈值后,开始拥塞避免(加法增大)
- 拥塞避免(加法增大):拥塞窗口cwnd 缓慢增大,以防止网络过早出现拥塞
- 乘法减小:只要出现网络拥塞,把ssthresh减为拥塞峰值的一半,同时执行慢开始算法(cwnd又恢复到初始值)
- 当网络出现频繁拥塞时,ssthresh值就下降的很快
TCP -【拥塞控制】- 快重传、快恢复
快重传:
- 接收方:
- 每接收到一个失序的分组就立即发送重复确认
- 使发送方能快速确认有分组没有到达
- 不需要等待自己再发送数据,再确认哪些数据丢失了(SACK)
- 发送方:
- 只要发送方连续接受到3个连续的确认(总共4个),就应当立即重传对方尚未接收到的报文段
- 不必继续等待重传计时器到期后再重传
- 接收方:
快恢复:
- 当发送方连续收到三个重复确认,说明网络出现拥塞
- 就执行 “乘法减小” 算法,把ssthresh(slow start threshold)减为拥塞峰值的一半
- 与慢开始不同之处是现在不执行慢开始算法,即cwnd现在不恢复到初始值
- 而是把cwnd值设置为新的ssthresh值(减小后的值)
- 然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大
快重传 + 快恢复
- 发送窗口的最大值swnd = min(接收窗口cwnd, 堵塞窗口rwnd)
- 当 rwnd < cwnd 时,是接收方的接收能力限制发送窗口的最大值
- 当 cwnd < rwnd 时,则是网络的拥塞限制发送窗口的最大值
- 发送窗口的最大值swnd = min(接收窗口cwnd, 堵塞窗口rwnd)
TCP的连接管理
TCP - 序号和确认号(详细步骤)
TCP - 【建立连接】- 3次握手
- 状态解读:
- 状态
- CLOSED:client处于关闭状态
- LISTEN:server处于监听状态,等待client连接
- SYN-RCVD:表示server接受到了SYN报文,当收到client的ACK报文后,它会进入到 ESTABLISHED 状态
- SYN-SENT:表示client已发送SYN报文,等待server的第2次握手ESTABLISHED:表示连接已经建立
- 前2次握手的相同点
- YN 都设置为1
- 数据部分的长度都为0
- TCP头部的长度一般是32字节
- 固定头部:20字节
- 选项部分:12字节
- 双方会交换确认一些信息
- 比如MSS、是否支持SACK、Window scale(窗口缩放系数) 等
- 这些数据都放在了TCP头部的选项部分中(12字节)
- 采用三次握手原因
- 主要目的:防止server端一直等待,浪费资源
- 当client发出的第一个连接请求报文段因为网络延迟(并且重发),
- 后续请求在服务器连接释放以后的某个时间才到达server,导致server端认为想建立新连接,并且服务器返回确认给客户端
- client对server确认不理睬
- 进而会导致server一直等待,浪费资源。
- 第三次握手失败处理
- 此时server的状态为
SYN-RCVD
,若等不到client的 ACK,server会重新发送 SYN+ACK 包 - 如果server多次重发 SYN+ACK 都等不到client的 ACK(也就是超时),就会发送 RST包,强制关闭连接(被杀死)
- 如果收到其他报文段或报文,就会发出差错报文。
- 此时server的状态为
- 状态解读:
TCP - 【释放连接】- 4次挥手
- 状态解读
- FIN-WAIT-1:表示想主动关闭连接
- 向对方发送了FIN报文,此时进入到FIN-WAIT-1状态
- CLOSE-WAIT:表示在等待关闭
- 当对方发送FIN给自己,自己会回应一个ACK报文给对方,此时则进入到CLOSE-WAIT状态
- 在此状态下,需要考虑自己是否还有数据要发送给对方,如果没有,发送FIN报文给对方
- FIN-WAIT-2:只要对方发送ACK确认后,主动方就会处于FIN-WAIT-2状态,然后等待对方发送FIN报文
- CLOSING:一种比较罕见的例外状态
- 表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN 报文
- 如果双方几乎在同时准备关闭连接的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态(不会进入FIN-WAIT-2状态,最终进入TIME-WAIT状态)
- 表示双方都正在关闭连接
- LAST-ACK:被动关闭一方在发送FIN报文后,最后等待对方的ACK报文
- 当收到ACK报文后,即可进入CLOSED状态了
- TIME-WAIT:表示收到了对方的FIN报文,并发送出了ACK报文,就等 2MSL 后即可进入CLOSED状态了
- 如果FIN-WAIT-1状态下,收到了对方同时带FIN标志和ACK标志的报文时
- 可以直接进入到TIME-WAIT状态,而无须经过FIN-WAIT-2状态
- CLOSED:关闭状态
- 由于有些状态的时间比较短暂,所以很难用
netstat
命令看到,比如SYN-RCVD、FIN-WAIT-1等
- 由于有些状态的时间比较短暂,所以很难用
- 归纳
- 前两次是关闭了客户端到服务器的发送通道,后两次是关闭了服务器到客户端的发送通道。
- 状态解读
相关补充
- TCP / IP 协议栈在设计上,允许任何一方先发起断开连接。
- 一般是等待2倍的 MSL(Maximum Segment Lifetime,最大分段生存期)(MSL是TCP报文段在Internet上的最长生存时间)
- 每个具体的TCP实现都必须选择一个确定的MSL值,RFC 1122建议是2分钟,可以防止本次连接中产生的数据包误传到下一次连接中(因为本次连接中的数据包都会在2MSL时间内消失了)
- 为什么会在Client发送确认Server的ACK后,需要有个TIME-WAIT阶段,等待一段时间后,然后再真正关闭连接?
- 如果客户端在发送完ACK后直接进入CLOSED 状态,中间可能因为网络原因,server丢失了client的ACK,就会重发FIN来释放连接也就会引发以下的两种状况:
- 客户端关闭了,没有任何反应,服务器就会等很久,甚至多次发送FIN报文,浪费资源。
- 客户端刚好打开一个应用程序分配和刚刚那个同一个端口,新的应用程序就会收到FIN,执行关闭连接的操作(本来是需要建立来连接的)
- 如果客户端在发送完ACK后直接进入CLOSED 状态,中间可能因为网络原因,server丢失了client的ACK,就会重发FIN来释放连接也就会引发以下的两种状况:
- 四次挥手的原因
- TCP是全双工模式的,双方同时可以发送和接收数据。
- 第一次挥手,表示主机1告诉主机2没有数据需要发送,此时主机1仍可以接收主机2的数据。
- 第二次挥手,表示主机2知道主机1没有数据需要发送,此时主机2仍可以发送数据到主机1。
- 第三次挥手,表示主机2告诉主机1没有数据需要发送
- 第四次挥手,表示主机1已经知道主机2没有数据发送了。随后正式断开整个TCP连接
- 有时通过抓包可以发现,又是后只有三次挥手,其实是将第二和第0三次挥手合并了,在接收到FIN的同时,通知没有数据需要发送了。
- 长连接和短连接(建立连接的目的)
- 长连接:客户端建立完连接,只需要拿完数据不断开(频繁数据交互)就是长连接。
- 短连接:客户端建立完连接,只需要拿完数据后立刻断开连接