TCP/IP协议相关
TCP/IP协议族
由一系列网络协议所组成的一个网络分层模型,是Internet的核心协议并被广泛应用于局域网和互联网。
分层
为什么要分层?
- 每层内部的设计可以自由改动,只需要修改替换对应分层即可
- 设计变得简单,分层只需要考虑当前的任务,不需要在意其他分层情况
- 网络的不稳定性
应用层(Application Layer)
向用户提供应用服务时通信的活动
相关协议:
- HTTP协议
- FTP协议-文件传输
- DNS协议-域名解析
传输层(Transport Layer)
提供处于网络连接中的两台计算机之间的数据传输
相关协议:
- TCP协议
- UDP协议
网络层(Internet Layer)
处理网络上流动的数据包,规定如何将数据包传送给对方
相关协议:
- IP协议
数据链路层(Link Layer)
处理连接网络的硬件部分,例如网卡、光纤等
物理层
例如,网线啥的
如何通信传输?
进行通信时,会按照分层顺序与对方进行通信。发送端数据从应用层向下走,接收端数据向应用层往上走。
如上图所示:
- 客户端向服务端发起请求
- 在应用层(HTTP协议)发送请求数据
- 传输层(TCP协议)接收到数据,并进行分割打上标记转发给网络层
- 网络层(IP协议),增加做为通信目的地的服务器MAC地址转发给链路层
- 链路层驱动硬件进行传输。
- 服务端接受客户端数据
- 链路层接收到数据
- 网络层继续向上转发数据到传输层
- 传输层向上转发到应用层
- 应用层接收到数据
- 一次HTTP请求完成
TCP协议
TCP协议位于传输层,提供可靠的字节流服务
字节流服务:方便数据的传输,将大块数据分割成
报文段
的数据包进行管理。
特点
特点 | 具体描述 |
---|---|
面向连接 | 使用TCP传输数据前,必须先建立TCP连接;传输完成后在释放连接 |
面向字节流 | 虽然应用程序和TCP的交互是一次一个数据块,但TCP只把数据看为一连串无结构的字节流。数据以流的形式传输 |
全双工通信 | 建立TCP连接后,通信双方都能发送数据 |
可靠 | TCP首部格式TCP传输的数据:不丢失、无差错、不重复,按序到达 |
TCP首部格式
源端口号
表示
发送端端口号
,字段长16位目标端口号
表示
接收端端口号
,字段长16位序列号
指的是本报文段第一个字节的序列号,长32位。每发送一次数据,就累加一次该数据的字节流大小。
序列号不会从0、1开始,而是以一个随机数作为初始值(ISN),通过SYN包发送给服务端。
主要作用如下:
- 在
SYN
报文中交换彼此的初始序列号(ISN
) - 保证数据报按正确的顺序发送
ISN:随机生成的一个初始值,在三次握手过程中双端互相交换。
ISN基本是每4ms加一,溢出则回到0,使猜测ISN过程变得困难。
以上操作是为了避免被攻击者预测到,防止攻击者伪造
RST
控制位,导致连接被强制关闭。- 在
确认号
表示
告知对方下一个期望接收的序列号
,长度为32位。小于确认号的所有字节已被全部正常接收。首部长度
表示
TCP传输的数据部分应该从TCP包的第几位开始计算
,等价于TCP首部的长度。剩下的都为数据长度保留
该字段是为了以后扩展时使用,长度为4位。
控制位/标记位
用来控制连接的流程
- CWR:控制拥塞窗口
- ECE:值为1时,通知通信对方当前网络有拥塞。
- URG:值为1时,表示包中有需要紧急处理的数据。
- ACK:确认应答的字段变为有效。TCP规定除了最初建立连接时的SYN包之外该值必须设置为1。
- PSH:若值为1,告知通信对方收到的数据应该直接上传到上层的应用层;若值为0,不需要立即上传而是先进行缓存。
- RST:值为1,表示TCP连接出现异常必须强制断开连接。
- SYN:用于建立连接,值为1表示希望建立连接,并进行初始序列号(
ISN
)的设置 - FIN:值为1,表示今后不会再有数据发送,希望断开连接。
窗口大小
长度为16位,用于通知从相同TCP首部的确认号所指位置开始能接收的数据大小
。告知对方允许发送的数据量。实际上该大小是不够用的。因此TCP支持
窗口缩放
选项,作为窗口缩放比例因子,范围在0~14
,可以扩大当前窗口值为2^n。校验和
长度为16位,防止传输过程中数据包有损坏,如果数据不正确,则等待重传。
紧急指针
长为16位,只有在
URG
控制位为1时才有效。表示
本报文段中紧急数据的指针——数据首位到紧急数据指针之间的都是紧急数据。
一般用于
暂时中断通信
可选项
主要用于提高TCP的传输性能。
类型 | 长度 | 意义 | 描述 |
---|---|---|---|
2 | 4 | Maximum Segment Size(MSS) | TCP允许从对方接收的最大报文段 |
3 | 3 | WSOPT-Window Scale | 扩大窗口,可提高吞吐量 |
5 | N | SACK | 选择确认选项 可以允许最大四次的方式确认应答,在数据时不时丢失的情况下,避免无用重发并提高重发速度。 |
8 | 10 | TSOPT-Time Stamp Option | 用于高速通信中对序列号的管理,可以区分新老序列号。 |
TSOPT-Time Stamp Option
:记录序列号发送时的内核时间在报文中。
格式:kind(1字节)+length(1字节)+info(8字节)
按照上表来看,
kind
为8,length
为10,info包含timestamp
和timestamp echo
。
可以解决以下两大问题:
计算往返时延(RTT)
- 客户端向服务端发送数据时,
timestamp
存储当前内核时间ta1
- 服务端回复客户端时,
timestamp
存放服务端内核时间tb
- 客户端收到数据时,可以解析得到
timestamp
为客户端内核时间ta2
,在解析timestamp echo
得到第一次发送时的内核时间ta1
,然后ta2-ta1
就是RTT
。
- 客户端向服务端发送数据时,
防止序列号的回绕问题
在传输不稳定的网络情况下,有可能会在较晚的时间内收到较早时发送的一个数据报,由于记录了
timestamp
那么可以比较timestamp
来判断是否同一个数据报。
*TCP连接建立——三次握手
过程
- 初始时,客户端与服务端都处于
CLOSED
状态,服务端为了提供服务,主动监听端口,然后进入LISTEN
状态 - 客户端主动发起连接(发起
SYN
包),进入SYN-SENT
状态。——第一次握手 - 服务端收到
SYN
包后,回复SYN、ACK
包,然后服务端进入SYN-RCVD
状态——第二次握手 - 客户端收到服务端发来的
SYN、ACK
包后,确认服务端通信建立,在回复ACK
包,并进入ESTABLISHED
状态;服务端接收到ACK
之后,也变成了ESTABLISHED
状态。——第三次握手
此时,双方进入了正常的数据传输过程。
- SYN:sunchronize,该包需要对端的确认
- ACK:acknowldgement
前两次握手过程中不能携带数据,第三次握手时可以携带数据。若有人在第一次发送的SYN
包时注入大量数据,势必导致服务端要耗费更多的资源进行数据处理,降低了服务器的性能。
拓展
为什么不能两次握手?
根本原因:无法确认客户端的接收能力。
当客户端发送SYN
后想进行第一次握手,但是由于网络原因导致该SYN
包滞留而没有发送到服务端。此时触发超时重传机制,于是客户端会重新发出SYN
包,由于是两次握手,客户端与服务端建好了连接。
但是过一段时间后,连接已经被关闭,这时上面被滞留的SYN
包就可能会发送到服务端,此时服务端继续发送SYN、ACK
包与客户端建立了连接。导致了连接资源的浪费。
TCP攻击
利用TCP的三次握手机制,模拟多个客户端对服务端发起连接请求(发送SYN
包),但是不处理服务端所返回的SYN、ACK
包,导致服务端一直处于一种半连接状态,大量消耗服务器资源,导致死机。
即使配置了超时重试功能,也会因为数量过大,导致无限等待。
这个就叫做SYN FLOOD攻击
,如何去应对上述攻击:
- 增加
SYN
连接数,想办法增加半连接队列
的容量 - 减少
SYN+ACK
重试次数,避免堆积大量的超时重发
任务 - 也可以利用
SYN Cookie
技术,服务端收到SYN
包后不先去分配资源,而是根据SYN
包计算出一个SYN Cookie
,在第二次握手时回复给客户端进行保存,这样在客户端回复ACK
时带上SYN Cookie
,服务端验证合法后就可以分配资源。
半连接/全连接队列
半连接队列:客户端发送SYN包
到服务端后,服务端会回复ACK、SYN
,并且切换状态至SYN-RECV
,该连接就会进入半连接队列
。
全连接队列:客户端接收到服务端的ACK、SYN
包后,三次握手即完成。这时,该连接就会加入至全连接队列
。
*TCP连接关闭——四次挥手
TCP断开连接——四次挥手
过程
- 初始时,客户端与服务端都处于
ESTABLISHED
状态并双向传输数据 - 客户端准备断开连接,然后发出
FIN
包并且指定一个seq序列号
,发出后客户端进入FIN-WAIT-1
状态——第一次挥手 - 服务端收到
FIN
包后,回复ACK
到客户端,并进入CLOSE-WAIT
状态;客户端在收到服务端的ACK
包后,也进入FIN-WAIT-2
状态,等待服务端的最终释放连接报文(FIN
)——第二次挥手 - 服务端此时也要准备断开连接,发送
FIN、ACK
包到客户端,表示自己准备断开连接,然后进入LAST-ACK
状态——第三次挥手 - 客户端收到
FIN、ACK
消息后,会回复ACK
包到服务端,并进入TIME-WAIT
状态。出于稳定和安全性考虑,客户端会等待2MSL
的时长,然后进入CLOSED
状态。服务端在收到客户端的ACK
包后,也进入CLOSED
状态。——第四次挥手
此时,双方都进入CLOSED
状态,表明正式断开了连接。
FIN:连接释放报文段
MSL:最长报文段寿命,表示任何报文段在网络上的最长存活时间,超过这个时间的报文都将被丢弃。
协议规定
MSL
为2分钟,常用的多是30s、1min、2min
拓展
为什么要四次挥手?
当关闭连接时,客户端发送FIN
报文到服务端,服务端先返回一个ACK
报文到客户端,但是不会关闭掉当前的连接,这也导致会出现第三次挥手的情况,必须等到服务端任务处理完毕,才能发送FIN
报文到客户端,通知客户端准备关闭。
如果服务端直接发送FIN、ACK
包,如果此时网络出现延迟就会导致客户端触发超时重传
一直发送FIN
包,浪费连接资源。
为什么需要等待2MSL
时间在关闭?
- 首先,客户端如果不等待
2MSL
而是直接关闭,就会导致服务端后续发送的包无法被接收,并且客户端端口已被其他使用,就会产生无用数据,导致数据包混乱 - 用一个
MSL
保证四次挥手中主动关闭方最后的ACK
报文可以到达对方,上面示例表示的就是客户端发出的ACK包可以被服务端接收
- 另一个
MSL
可以保证已失效的连接请求报文段不会出现在连接中,避免下一个新的连接出现旧的连接请求报文。
TCP状态机
将连接建立和断开的两个时序状态图结合起来,就是
TCP状态机
。
TCP快速打开——TCP Fast Open
TCP快速打开为了优化后续的TCP握手流程,快速建立连接。——TFO
主要利用的原理就是SYN Cookie
在第一次建立连接时,服务端会计算得出一个SYN Cookie
,然后放置于SYN、ACK
数据包中的FAST OPEN
选项返回给客户端,客户端收到SYN、ACK
数据包时,解析FAST_OPEN
选项,缓存其中的Cookie。
在后续建立连接的过程中,客户端会直接发送SYN包、HTTP请求以及SYN Cookie
到服务端,只要服务端验证SYN Cookie
通过,就会返回SYN、ACK
包以及HTTP请求的响应数据
。
*可靠性保证
无论对方以多快的的速度发送数据,接收方总来得及处理收到的数据
核心思想
- 出错重传:出现错误时,让发送方重新发送数据
- 速度匹配:当接收方来不及处理接收的数据时,通知发送方降低数据传输速率。
流量控制
接收方根据自己接收缓存的大小,动态调整发送窗口的大小,从而控制对方的发送速率。
滑动窗口协议
传输层进行流量控制的一种措施,接收方通过告知发送方自己的窗口大小,从而控制对方的发送速率,达到防止对方数据发送过快导致自己处理不完的问题。
滑动窗口分为以下两部分
发送窗口
任意时刻,发送方维持的一组连续的,允许发送帧的帧序号。
其中黑框部分就是发送窗口。是由下面的
已经发送但没有收到确认帧
和未发送但可以发送数据
这两部分组成。发送窗口包含以下四大部分:
- 已经发送并收到确认帧(
Sent and Acknowledged
) - 已经发送但没收到确认帧(
Sent but not yet Acknowledged
) - 未发送但可以发送(
Not sent Recipient Ready to Receive
) - 未发送且不能发送(
Not send and not ready to receive
)
每收到一个接收方返回的确认帧,发送窗口就向前移动一帧。当
发送窗口
里都为已经发送但没收到确认帧
,那么发送窗口
停止发送数据,直到收到接收方发出的确认帧则继续向后移动,直到发送窗口内无数据可以发送。- 已经发送并收到确认帧(
接收窗口
任意时刻,接收方维持的一组连续的,允许接收帧的帧序号。
其中黑框部分就是接收窗口。是由下面的
未接受准备接收数据帧
组成。接收窗口包含以下三大部分:
- 已接收数据帧
- 未接收但准备接收数据帧
- 未接收且未准备接收数据帧
每收到一个发送方发送的数据帧,接收窗口就向前移动一帧,并返回确认帧到发送端。
若收到的数据帧不在接收窗口内,则丢弃该数据帧。
流量控制过程
- 接收端向发送端通知自己可以接收的数据的大小
a
- 发送端就会发送不超过
a
大小的数据 - 后续,接收端缓冲区面临溢出时,又会通知一个更小的窗口值
b
到发送端 - 发送端收到通知后再发送不超过
b
大小的数据
可能出现的问题
若接收端发给发送端的窗口调整通知
中途丢失的话,可能会导致无法继续通信,甚至出现死锁问题(由于发送方一直等待接收方的窗口通知,然后接收方一直等到发送方的数据)。
解决方案:
TCP为每一个连接设计持续计时器,只要TCP发送方收到零窗口通知
,就启动该计时器。若计时器结束,则会发出一个零窗口探测
的数据报,等待对方给出窗口大小
。为0则重新设置计时器,不为0则打破死锁状态。
死锁的形成条件:
- 互斥条件:一个资源每次只能被一个进程使用
- 占有且等待:一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 不可强行占有:进程已获得的资源,未使用完之前不能强行剥夺
- 循环等待:若干进程形成一种头尾相接的循环等待资源关系。
拥塞控制
防止过多的数据注入到网络中,使得网络中的路由器和链路不至于过载。
拥塞窗口(cwrd)
指目前自己还能传输的数据量大小
接收窗口
与拥塞窗口
都是接收端上的概念,两者计算后可以得出发送窗口
的大小。
1 |
|
慢启动
当主机开始发送数据时,由小到大逐渐增加拥塞窗口(发送窗口)数值,从而由小到大逐渐增大发送报文段。
得到的是慢启动阈值(ssthresh),当发送窗口到达这个阈值时,就先暂停一下发送。
拥塞避免
当发送窗口到达慢启动阈值时,使得
拥塞窗口
大小按规律线性增长。每经过一轮RTT(往返时延)
,拥塞窗口大小+1。
快速重传
TCP传输的过程中,如果发生了丢包——接收端发现数据端不是按序到达,那么就需要发送端重新发送丢失的数据。
例如发送了4 5 6 7
四个数据报到接收端,但是接收端没有收到5
,通常的情况下需要发送端等待一个RTO(超时重传时间)
然后重新发送4 5 6 7
数据报。
当发送方至少收到3个重复的ACK时,意识到丢包了,就会立即重新重传对方尚未收到的报文段,而不用等待一个
RTO
。
选择性重传
当接收端已经收到了部分数据时,回复发送端
ACK
报文时,可以设置可选项(Option)
,加上SACK
熟悉,通过left edge
、right edge
告知发送端已接收的数据范围。然后发送端就会发送不在该范围内的数据给接收端,减少数据量。
快速恢复
当发送端接收到三次重复ACK之后,就会发现传输过程中出现了数据丢失,就会进入
快速恢复
阶段。
- cwnd大小缩小为当前的一半
ssthresh
设置为缩小后的cwnd
大小- cwnd大小线性增加
提高网络利用率
Nagle算法
发送端即使还有应该发送的数据,但如果这部分的数据还很少的话,则进行延迟发送。
主要为了避免小包的频繁发送。
立即发送条件
- 已发送的数据都已经收到确认应答时
- 数据包发送的大小达到
MSS(最大报文长度)
时
可能的问题
可能产生某种程度的延迟。可以通过设置TCP_NODELAY
关闭该算法。
延迟确认
接收端收到数据以后并不立即返回确认应答(
ACK
),而是等待一定时间内合并多个ACK
在回复给发送端。
TCP要求这个时延必须小于500ms(可能导致发送端重新发送数据),一般操作系统不会设置超过200ms。
立即回复条件
- 需要调整发送窗口大小
- TCP处于
quickack
模式,通过tcp_in_quickack_mode
开启 - 发现了乱序包
UDP协议
UDP协议位于传输层,但不保证可靠性。
特点
UDP特点 | 具体描述 |
---|---|
无连接 | 使用UDP传输数据,不需要建立连接 |
不可靠 | UDP的数据包发送后,不管其是否会到达接收方 |
面向报文 | 数据 以数据报文(包)的形式传输 |
无拥塞控制 | 由于是不可靠传输,不管是否到达接收方,所以不需要拥塞控制 |
UDP首部格式
源端口号
表示
发送端端口号
,长16位
。可以不设置该端口号,默认为
0
,表示单方面发送消息,不需要接受端的返回信息。目标端口号
表示
接收端端口号
,长16位
。UDP包长度
保存了
UDP首部的长度和数据的长度之和
。UDP校验和
为了提供可靠的
UDP首部和数据而设计
。检测用户数据报在传输过程中是否有错。
TCP、UDP的区别
TCP是
面向连接
的,UDP是面向无连接的所谓连接,是为了在客户端和服务端之间建立连接,而建立一定的数据结构来维护双方交互的状态,用这样的数据结构来保证所谓的面向连接的特性。
TCP
提供可靠交付
,通过TCP
传输的数据,不丢失、无差错、不重复,按序到达。而UDP继承了IP包的特性,不保证不丢失,不保证按序到达。TCP是
面向字节流
的,把每个数据块看为一串无结构的字节流
,方便进行维护;而UDP继承IP包特性,基于数据报
的,一个个的向外发或者接收。TCP是有
拥塞控制
的,意识到丢包或者网络环境不好时,会调整自己的行为,调整发包频率;UDP只要有包就会发送,无论是否到达接收方。TCP是
有状态
的服务,会记录当前状态,例如包是否发送,该发送哪个;UDP是无状态的,不会记录下来
适用场景
- 需要资源少,在网络情况比较好的内网,或者对于丢包不敏感的应用
- 不需要一对一沟通,建立连接,而是可以广播的应用
- 需要处理速度快,时延低,可以容忍少数丢包,但是要求即便网络堵塞,也不能受到影响。
例如:流媒体的协议(视频播放)
、实时游戏
、IoT物联网
、移动通信领域(语言、视频通话)
。
QUIC协议
Google提出的一种基于UDP改进的通信协议,目的是降低网络通信的延迟,提供更好的用户体验。该协议位于
应用层
上。
- 自定义连接机制
- 自定义重传机制
- 无阻塞的多路复用
- 自定义流量控制
IP协议
IPV4
Internet Protocol Version4
采用32位构成
示例:
192.168.2.250
IPV6
Internet Protocol version 6
采用128位构成,按照每16位划分为一个段,将每个段转换为
16进制
,并用冒号隔开示例:
2404:6800:4012:200e
参考内容
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!