学习协议的阶段总结
目录
TCP网络分层
网络五层协议
应用层:应用之间的协议
传输层:端到端 (客户端:临时端口 服务器:目标端口号) 可靠连接
网络互联层:主要通过IP协议进行传输,IP 到 IP 源地址传到目标地址
网络访问层: 网络、硬件相关,传输通过以太网(当今现有局域网采用的最通用的通信协议标准)
在 TCP/IP 中包含一系列用于处理数据通信的协议:
- TCP (传输控制协议) - 应用程序之间通信
- UDP (用户数据报协议) - 应用程序之间的简单通信
- IP (网际协议) - 计算机之间的通信
- ICMP (因特网消息控制协议) - 针对错误和状态
- DHCP (动态主机配置协议) - 针对动态寻址
TCP头信息:
- TCP端口号
TCP的连接是需要四个要素确定唯一一个连接:
(源IP,源端口号)+ (目地IP,目的端口号)
所以TCP首部预留了两个16位作为端口号的存储,而IP地址由上一层IP协议负责传递
源端口号和目地端口各占16位两个字节,也就是端口的范围是2^16=65535
另外1024以下是系统保留的,从1024-65535是用户使用的端口范围
- TCP的序号和确认号:
32位序号 seq:Sequence number 缩写seq ,TCP通信过程中某一个传输方向上的字节流的每个字节的序号,通过这个来确认发送的数据有序,比如现在序列号为1000,发送了1000,下一个序列号就是2000。
32位确认号 ack:Acknowledge number 缩写ack,TCP对上一次seq序号做出的确认号,用来响应TCP报文段,给收到的TCP报文段的序号seq加1。
- TCP的标志位
每个TCP段都有一个目的,这是借助于TCP标志位选项来确定的,允许发送方或接收方指定哪些标志应该被使用,以便段被另一端正确处理。
用的最广泛的标志是 SYN,ACK 和 FIN,用于建立连接,确认成功的段传输,最后终止连接。
- SYN:简写为
S
,同步标志位,用于建立会话连接,同步序列号; - ACK: 简写为
.
,确认标志位,对已接收的数据包进行确认; - FIN: 简写为
F
,完成标志位,表示我已经没有数据要发送了,即将关闭连接; - PSH:简写为
P
,推送标志位,表示该数据包被对方接收后应立即交给上层应用,而不在缓冲区排队; - RST:简写为
R
,重置标志位,用于连接复位、拒绝错误和非法的数据包; - URG:简写为
U
,紧急标志位,表示数据包的紧急指针域有效,用来保证连接不被阻断,并督促中间设备尽快处理
TCP三次握手建立连接
有效节约服务器资源
- 第一次握手:
客户端将TCP报文标志位SYN置为1,随机产生一个序号值seq=x,保存在TCP首部的序列号(Sequence Number)字段里,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端,发送完毕后,客户端进入SYN_SENT
状态,等待服务器端确认。 - 第二次握手:
服务器端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务器端将TCP报文标志位SYN和ACK都置为1,ack=x+1,随机产生一个序号值seq=y,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD
状态。 - 第三次握手:
客户端收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=y+1,并将该数据包发送给服务器端,服务器端检查ack是否为y+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED
状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。
注意:我们上面写的ack和ACK,不是同一个概念:
- 小写的ack代表的是头部的确认号Acknowledge number, 缩写ack,是对上一个包的序号进行确认的号,ack=seq+1。
- 大写的ACK,则是我们上面说的TCP首部的标志位,用于标志的TCP包是否对上一个包进行了确认操作,如果确认了,则把ACK标志位设置成1。
TCP四次挥手关闭连接
是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。
在socket编程中,这一过程由客户端或服务端任一方执行close来触发。由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。
挥手请求可以是Client端,也可以是Server端发起的,我们假设是Client端发起:
- 第一次挥手: Client端发起挥手请求,向Server端发送标志位是FIN报文段,设置序列号seq,此时,Client端进入
FIN_WAIT_1
状态,这表示Client端没有数据要发送给Server端了。 - 第二次分手:Server端收到了Client端发送的FIN报文段,向Client端返回一个标志位是ACK的报文段,ack设为seq加1,Client端进入
FIN_WAIT_2
状态,Server端告诉Client端,我确认并同意你的关闭请求。 - 第三次分手: Server端向Client端发送标志位是FIN的报文段,请求关闭连接,同时Server端进入
LAST_ACK
状态。 - 第四次分手 : Client端收到Server端发送的FIN报文段,向Server端发送标志位是ACK的报文段,然后Client端进入
TIME_WAIT
状态。Server端收到Client端的ACK报文段以后,就关闭连接。此时,Client端等待2MSL的时间后依然没有收到回复,则证明Server端已正常关闭,那好,Client端也可以关闭连接了。
为什么要等待2MSL?
MSL:报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。
- 1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端
- 1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达
- 2MS = 去向 ACK 消息最大存活时间(MSL) + 来向 FIN 消息的最大存活时间(MSL)
服务端的ACK 和 FIN 不可以合并发。服务端可能还会有没有处理完的数据和需要发送的数据包,所以ACK 和 FIN 的发送往往有一定的时延,客户端迟迟收不到ACK,就会每隔一段时间进行重发FIN,导致连接错乱
为什么 SYN/FIN 不包含数据却要消耗一个序列号
凡是需要对端确认的,一定消耗TCP报文的序列号(两端的确认)
解决网络原因导致的重传问题,对需要处理的请求进行排序
半连接队列和 SYN Flood攻击
在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:
- 半连接队列,也称 SYN 队列;
- 全连接队列,也称 accepet 队列;
服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应 SYN+ACK,接着客户端会返回 ACK,服务端收到第三次握手的 ACK 后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到 accept 队列,等待进程调用 accept 函数时把连接取出来。
不管是半连接队列还是全连接队列,都有最大长度限制,超过限制时,内核会直接丢弃,或返回 RST 包。
SYN Flood 攻击原理
三次握手 属于一个协商的过程,客户端与服务端必须严格按照这个过程来进行,否则连接就不能建立。
这时,如果客户端发送 SYN包 企图与服务端建立连接,但发送完 SYN包 后就不管,那会发送什么事情呢?
客户端发送一个 SYN包 给服务端后就退出,而服务端接收到 SYN包 后,会回复一个 SYN+ACK包 给客户端,然后等待客户端回复一个 ACK包。
但此时客户端并不会回复 ACK包,所以服务端只能一直等待直到超时。服务端超时后,会重发 SYN+ACK包 给客户端,默认会重试 5 次,而且每次等待的时间都会增加(可以参考 TCP 协议超时重传的实现)。
另外,当服务端接收到 SYN包 后,会建立一个半连接状态的 Socket。所以,当客户端一直发送 SYN包,但不回复 ACK包,那么将会耗尽服务端的资源,无法处理正常请求这就是 SYN Flood 攻击。
TCP快速打开 TFO原理
是TCP的拓展协议,原理为在发送第一个 SYN包的时候就开始传输数据了,不过要求当前客户端和服务端已经完成过一次三次握手
TFO 分为两个阶段
请求 Fast Open Cookie
TCP Fast Open
检验不合法 丢弃包 进行正常的三次握手
优势:减少一个RTT,防止SYN Flood攻击 RTT(Round-Time Trip )
学习视频直达:为什么 SYNFIN 不包含数据却要消耗一个序列号?_哔哩哔哩_bilibili
参考博客: