TCP结构:
SYN是同步的缩写,SYN 段是发送到另一台计算机的 TCP 数据包,请求在它们之间建立连接
ACK 是“确认”的缩写。 ACK 数据包是任何确认收到一条消息或一系列数据包的 TCP 数据包
TCP三次握手如图:

1.1第一次握手
客户端给服务器发送一个SYN标志位为1的 TCP/IP 数据包, 该包中客户端的初始序列号(Sequence number = J)。
1.2第二次握手
服务器返回客户端 SYN +ACK两个标志位都为为1的 TCP/IP 数据包,该包中服务器的初始序列号(Sequence number = K);同时使 Acknowledgment number = J + 1来表示确认已收到客户端的 SYN段。
1.3第三次握手
客户端给服务器响应一个ACK标志位为1的 TCP/IP 数据包, 该包中使 Acknowledgment number = K + 1来表示确认已收到服务器的 SYN段。
解释一下 三次握手 和 四次挥手?
三次握手:

第一次:客户端向服务器发送syn包,此时进入[SYN_SENT]状态,等待服务器返回信息;此时服务端确认了客户端发送是正常的
第二次:服务器收到syn包,需要确认客户端的syn包,同时自己发出一个syn+ask包给客户端;此时客户端知道了自己发送、接收正常,客户端也知道服务器发送接收也正常;但是服务器不知道客户端接收是否正常,也不知道自己发送是否正常。
第三次:[客户端]收到服务器的syn+ask包后,向服务器发送确认包ask,此包发送完毕,客户端和服务器进入[ESTABLISHED](TCP连接成功)状态;双方都知道对方发送和接收都正常。
为什么不能两次握手:
假如A发出了一个由于网络异常变成了失效的连接a;当a到达B,那么只要B确认,新的连接就建立了。B会一直等待A发送数据,这样就造成了资源浪费。
为什么不能四次握手:
3次就可以解决问题了,为什么要四次
TCP三次握手详细解析过程:

1.1 第一次握手
客户在socket() connect()后主动(active open)连接上服务器, 发送SYN ,这时客户端的状态是SYN_SENT
服务器在进行socket(),bind(),listen()后等待客户的连接,收到客户端的 SYN 后,
1.1.1 半连接队列(syn queue)未满
服务器将该连接的状态变为SYN_RCVD, 服务器把连接信息放到半连接队列(syn queue)里面。
1.1.2 半连接队列(syn queue)已满
服务器不会将该连接的状态变为SYN_RCVD,且将该连接丢弃(SYN flood攻击就是利用这个原理,
对于SYN foold攻击,应对方法之一是使syncookies生效,将其值置1即可,路径/proc/sys/net/ipv4/tcp_syncookies,
即使是半连接队列syn queue已经满了,也可以接收正常的非恶意攻击的客户端的请求,
1.2 第二次握手
服务器返回SYN+ACK段给到客户端,客户端收到SYN+ACK段后,客户端的状态从SYN_SENT变为ESTABLISHED,
也即是connect()函数的返回。
1.3 第三次握手
全连接队列(accept queue)的最大值 /proc/sys/net/core/somaxconn (默认128)
1.3.1 全连接队列(accept queue)未满
服务器收到客户端发来的ACK, 服务端该连接的状态从SYN_RCVD变为ESTABLISHED,
然后服务器将该连接从半连接队列(syn queue)里面移除,且将该连接的信息放到全连接队列(accept queue)里面。
1.3.2 全连接队列(accept queue)已满
服务器收到客户端发来的ACK, 不会将该连接的状态从SYN_RCVD变为ESTABLISHED。
当然全连接队列(accept queue)已满时,则根据 tcp_abort_on_overflow 的值来执行相应动作
SYN flood攻击
攻击方的客户端只发送SYN分节给服务器,然后对服务器发回来的SYN+ACK什么也不做,直接忽略掉,
不发送ACK给服务器;这样就可以占据着服务器的半连接队列的资源,导致正常的客户端连接无法连接上服务器。
(SYN flood攻击的方式其实也分两种,第一种,攻击方的客户端一直发送SYN,对于服务器回应的SYN+ACK什么也不做,不回应ACK, 第二种,攻击方的客户端发送SYN时,将源IP改为一个虚假的IP, 然后服务器将SYN+ACK发送到虚假的IP, 这样当然永远也得不到ACK的回应。)
https://blog.csdn.net/jun2016425/article/details/81506353
四次挥手:

假设Client端发起中断连接请求,也就是发送FIN报文。
Server端接到FIN报文后,意思是说”我Client端没有数据要发给你了”,但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以 Server 端会先发送ACK,”告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息”。这个时候Client端就进入 FIN_WAIT 状态,继续等待Server端的FIN报文。
当Server端确定数据已发送完成,则向Client端发送FIN报文,”告诉Client端,好了,我这边数据发完了,准备好关闭连接了”。
Client端收到FIN报文后,”就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送 ACK 后进入 TIME_WAIT 状态,如果 Server 端没有收到 ACK 则可以重传“,Server端收到ACK后,”就知道可以断开连接了”。
Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了!
整个过程:
A向B发起请求,表示A没有数据要发送了:A——>B;
B向A发送信号,确认A的断开请求请求:B——>A;
B向A发送信号,请求断开连接,表示B没有数据要发送了:B——>A;
A向B发送确认信号,同意断开:A——>B。
为什么2、3次挥手不能合在一次挥手中?那是因为此时A虽然不再发送数据了,但是还可以接收数据,B可能还有数据要发送给A,所以两次挥手不能合并为一次。
为什么挥手次数比握手多一次? 是因为握手过程,通信只需要处理连接。而挥手过程,通信需要处理数据+连接。