在网络数据传输中,传输层协议TCP是要建立连接的可靠传输,TCP建立连接的过程,我们称为三次握手。
SYN
置1,随机产生一个初始序列号 seq
发送给服务端,进入SYN_SENT
状 态。SYN=1
之后,知道客户端请求建立连接,将自己的SYN
置1,ACK 置1,产生一个acknowledge number=sequence number+1
,并随机产生一个自己的初始序列号seq
,发送给客户端;进入SYN_RCVD
状态。acknowledge number
是否为序列号+1,ACK
是否为1,检查正确之后将 自己的ACK
置为1,产生一个acknowledge number=服务器发的序列号+1
,发送给服务器,进入 ESTABLISHED
状态。
服务器检查ACK
为1和acknowledge number
为序列号+1之后,也进入 ESTABLISHED
状态。完成三次握手,连接建立。
简单来说:
三次握手的目的是建立可靠的通信信道,主要的目的就是 双方确认自己与对方可以正常发送与接收。
所以三次握手就能确认双发收发功能都正常,缺一不可。
不可以
因为可能会出现已失效的连接请求报文段又传到了服务器端。
客户端 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达服务端。本来这是一个早已失效的报文段。但 服务端 收到此失效的连接请求报文段后,就误认为 是 客户端 再次发出的一个新的连接请求。于是就向 客户端 发出确认报文段,同意建立连接。
假设 不采用 “三次握手”,那么只要 服务端 发出确认,新的连接就建立了。由于现在 客户端 并没有发出 建立连接的请求,因此不会理睬 服务端 的确认,也不会向 服务端 发送数据。但 服务端 却以为新 的运输连接已经建立,并一直等待 客户端 发来数据。这样,服务端 的很多资源就白白浪费掉了。
采用 “三次握手” 的办法可以防止上述现象发生。例如刚才那种情况,客户端 不会向 服务端的确认 发出确认。服务端 由于收不到确认,就知道 客户端 并没有要求建立连接。
而且,两次握手无法保证 客户端 正确接收第二次握手的报文(服务端 无法确认 客户端 是否收到), 也无法保证 客户端 和 服务端 之间成功互换初始序列号。
这个肯定可以。三次握手都可以保证连接成功了,何况是四次,但是会降低传输的效率。
ACK number
,进入 ESTABLISH
状态。CLOSED
状态之后,如果客户端向服务器发送数据,服务器会以RST包应答。服务器每收到一次客户端的请求后都会重新复位一个计时器,时间通常是设置为2小时,若两小时 还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
TCP连接的一方A,随机选择一个32位的序列号(Sequence Number)作为发送数据的初始序列号(Initial Sequence Number,ISN),比如为1000,以该序列号为原点,对要传送的数据进行 编号:1001、1002... 三次握手时,把这个初始序列号传送给另一方B,以便在传输数据时,B可以确认什么样的数据编号是合法的;同时在进行数据传输时,A还可以确认B收到的每一个字节,如果A收到了B的确认编号(acknowledge number)是2001,就说明编号为1001-2000的数据已经被B成功接受。
SYN洪泛攻击属于 DOS 攻击的一种,它利用 TCP 协议缺陷,通过发送大量的半连接请求,耗费 CPU 和内存资源。
原理:
[SYN/ACK]
包(第二个包)之后、收到客户端的 [ACK]
包(第三个包)之前的 TCP 连接称为半连接(half-open connect),此时服务器处于 SYN_RECV
(等待客户端响应)状态。如果接收到客户端的 [ACK]
,则 TCP 连接成功,如果未接受到,则会不断重发请求直至成功。[SYN]
包,服务器回复 [SYN/ACK]
包,并等待客户的确认。由于源地址是不存在的,服务器需要不断的重发直至超时。[SYN]
包将长时间占用未连接队列,影响了正常的 SYN,导致目标系统运行缓慢、网络堵塞甚至系统瘫痪。检测:
当在服务器上看到大量的半连接状态时,特别是源 IP 地址是随机的,基本上可以断定这是一次 SYN 攻击。
防范:
在网络数据传输中,传输层协议断开连接的过程我们称为四次挥手。
FIN
置为1,发送一个序列号seq
给 服务端并进入FIN_WAIT_1
状态;FIN
之后,发送一个ACK=1
,acknowledge number=收到的序列号+1
并 进入CLOSE_WAIT
状态。
此时客户端已经没有要发送的数据了,但仍可以接受服务器发来的数据。FIN
置1,发送一个序列号客户端;进入LAST_ACK
状态。FIN
后,进入TIME_WAIT
状态;
接着将ACK
置1,发送一个 acknowledge number=序列号+1
给服务器;
服务器收到后,确认acknowledge number
后,变为 CLOSED
状态,不再向客户端发送数据。
客户端等待2 * MSL(报文段最长寿命)
时间后,也进入 CLOSED
状态。
完成四次挥手。四次挥手断开连接是因为要确定数据全部传输完了。
为什么不能把服务器发送的ACK和FIN合并起来,变成三次挥手,CLOSE_WAIT状态意义是什么?
因为服务器收到客户端断开连接的请求时,可能还有一些数据没有发完,这时先回复ACK,表示接收到了断开连接的请求。等到数据发完之后再发FIN,断开服务器到客户端的数据传送。
客户端没有收到ACK确认,会重新发送FIN请求。
第四次挥手时,客户端发送给服务器的ACK有可能丢失,TIME_WAIT状态就是用来重发可能丢失的 ACK报文。
如果 服务端 没有收到ACK
,就会重发FIN
,如果 客户端 在 2*MSL(报文段最长寿命)
的时间内收到了FIN
,就会重新发送ACK并再次等待2 * MSL
,防止服务端没有收到ACK
而不断重发FIN
。
MSL(Maximum Segment Lifetime),指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的 最大时间。如果直到2MSL,客户端 都没有再次收到FIN
,那么 客户端 推断ACK
已经被成功接收,则 结束TCP
连接。
TIME-WAIT 状态过多会产生什么后果?怎样处理?
解决方法:
SO_REUSEADDR
套接字选项来避免 TIME_WAIT状态,此套接字选项告诉内核,即使此端口正忙(处于TIME_WAIT状态),也请继续并重用它。/etc/sysctl.conf
文件,即修改net.ipv4.tcp_tw_reuse 和 tcp_timestamps
net.ipv4.tcp_tw_reuse = 1 # 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭; net.ipv4.tcp_tw_recycle = 1 # 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。TIME_WAIT 是主动断开连接的一方会进入的状态,一般情况下,都是客户端所处的状态,服务器端一般设置不主动关闭连接。
TIME_WAIT 需要等待 2*MSL
,在大量短连接的情况下,TIME_WAIT会太多,这也会消耗很多系统资源。对于服务器来说,在 HTTP 协议里指定 KeepAlive(浏览器重用一个 TCP 连接来处理多个 HTTP 请求),由浏览器来主动断开连接,可以一定程度上减少服务器的这个问题。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。