一、TCP 头部数据结构
(一)TCP头部数据结构:
【源端口号16位】 | 【目标端口号16位】
seq(序列号32位):序列号,用于将多个数据包进行排序,形成一个完整有序的数据流
ack(确认应答号32位):
SYN(报文):1表示连接请求或是连接接收请求 synchronize sequence numbers 同步序列编号
ACK(报文):1表示确认号字段有效 acknowledge character 确认字符
FIN(报文):请求断开,0表示不请求,1表示没有数据传输
RST(报文):连接状态,0表示正常,1表示异常
【数据】
(二)TCP头部数据结构(表图):![](https://i-blog.csdnimg.cn/direct/c6ca0e092b82431e8f1cb9ca42ec4c68.png)
二、TCP三次握手
(一)简单描述三次握手过程
第一次握手
【客户端】to【服务端】:【SYN报文】 seq = client_isn(客户端序列号) #客户端处于:SYN_SEND状态
第二次握手
【服务端】to【客户端】:【SYN,ACK报文】 ack = client_isn + 1 seq = server_isn(服务端序列号) #服务端处于:SYN-RCVD状态
第三次握手发送
【客户端】to【服务端】:【ACK报文】 ack = server_isn + 1 seq = client_isn +1 #客户端处于:ESTABLISHED状态
**第三次握手是可以携带数据的,前两次握手是不可以携带数据的**
(二)简单抽象的描述三次握手
1,c->s
- SYN
- seq
2,s->c
- SYN
- ACK
- seq
- ack
3,c->s
- ACK
- seq
- ack
(三)TCP 三次握手表图如下:
3.1 抓包截图
三、TCP四次挥手
(一)简单描述四次挥手过程
#第一次挥手
【客户端】to【服务端】:【FIN,ACK】, seq = 序列号X , ack = y#客户端进入FIN_WAIT_1状态
#第二次挥手
【服务端】to【客户端】:【ACK】 seq = y , ack = x+1#服务端发送完成进入CLOSE_WAIT状态、客户端接收成功进入FIN_WAIT_2状态
#第三次挥手
【服务端】to【客户端】:【FIN】 seq = y , ack = x+1#服务器发送完成进入LAST_ACK状态
#第四次挥手
【客户端】to【服务端】:【ACK】 seq = x+1,ack = y+1#客户端发送完成进入TIME_WAIT状态,服务端接收成功进入CLOSE状态
(二)简单抽象的描述四次挥手
1,s -> c
- FIN
- seq
- ack
2,c -> s
- ACK
- seq
- ack
3,c -> s
- FIN
- ack
- seq
4,s -> c
- ACK
- ...
(三)TCP 四次挥手表图如下:
3.1 抓包截图如下:
四、TCP三次握手状态变化
(一)简单画画三次握手状态变化
五、TCP四次挥手状态变化
(一)简单画画四次挥手状态变化
六、三次握手全部状态
(一)CLOSED状态
服务端和客户端初始状态
(二)SYN_SEND状态
1)客户端发送SYN后,状态转为SYN_SENT
2)客户端通过应用程序调用connect进入active open.发送SYN报文建立连接,之后状态置为SYN_SENT
(三)LISTEN状态
1)服务端收到客户端SYN(请求报文)。
2)服务端打开一个socket进行监听,状态置为LISTEN(监听)。
(四)SYN_RCVD状态
1)服务端给客户端发送SYN(请求报文)ACK ,状态转为SYN_RCVD.
2)A connection request has been received fromthenetwork.
(五)ESTABLISHED状态
1)服务器SYN_RECVD状态,收到ACK后,状态为ESTABLISHED;
2)客户端SYN_SENT状态,收到SYN、ACK后,发送ACK,状态转变为ESTABLISHED;
3)The socket has anestablishedconnection.
(六)拓展了解
1.如何避免SYN攻击?
调大netdev_max_backlog
增大TCP半连接队列
开启tcp_syncookies
减少SYN+ACK重传次数
六、四次挥手的全部状态
(一)ESTABLISHED状态
连接传输数据中
(二)FIN_WAIT_1状态
1)FIN_WAIT_1只出现在主动关闭的那一端,表示等待对方的FIN报文。
2)FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。对方回应ACK报文后,则进入FIN_WAIT_2状态。
3)实际无论对方何种情况下,都应该马上回应ACK报文,导致有可能见不到FIN_WAIT_1状态。
(三)FIN_WAIT_2状态
1)主动关闭的一端FIN_WAIT_1状态,得到对方返回ACK报文,就进入FIN_WAIT_2状态;
2)进入FIN_WAIT_2状态后,在没有拿到FIN报文之前,说明服务器端还有数据传输,那此时为半连接。
(四)CLOSE_WAIT状态
服务器端在收到 FIN 后,发送 ACK,状态为 CLOSE_WAIT;如果此时服务器端还有数据需要发送,那么就发送,直到数据发送完毕;此时,服务器端发送FIN,状态变为 LAST_ACK;
(五)LAST_ACK状态
last_ack(持续时间一般为一个RTO(retransmission timeout,数据包重传的timeout时间)的时间,这个时间根据RTT动态计算出来)有两个作用:作用一是处理重用连接:防止前一个连接上延迟的数据包或者丢失重传的数据包,被后面复用的连接(前后两次连接的协议相同,ip相同,端口号相同,且包的seq号也恰巧相同)错误的接收,则发送rst,重置连接;作用二是在发送第二个fin之后,如果在RTO之后,还没收到ack,则重发fin。
(六)TIME_WAIT状态
FIN_WAIT_1进入:此时应用程序端口收到 FIN+ACK(而不是像 FIN_WAIT_2 那样只收到 ACK,说明数据已经发送完毕)并向服务器端口发送 ACK;
FIN_WAIT_2进入:此时应用程序端口收到了 FIN,然后向服务器端发送 ACK;TIME_WAIT 是为了实现 TCP 全双工连接的可靠性关闭,用来重发可能丢失的 ACK 报文;需要持续 2 个 MSL (最大报文生存时间):假设应用程序端口在进入 TIME_WAIT后,2 个 MSL 时间内并没有收到FIN,说明应用程序最后发出的 ACK 已经收到了;否则,会在 2 个 MSL 内在此收到ACK报文;
(七)CLOSE状态
服务器LAST_ACK状态接受ACK包后,会等待一段时间2MSL,以确保所有的数据包都已经被对方接受和处理,保证通信的可靠和稳定。
(八)拓展了解
1.TIME_WAIT过多有什么危害?
第一是占用系统资源,比如文件描述符、内存资源、CPU资源、线程资源等
第二是占用端口资源,端口资源也是有限的,一般可以开启的端口为32768~61000,也可以通过net.ipv4.ip_local_port_range参数指定范围。
2.如何优化TIME_WAIT?
打开net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps选项
net.ipv4.tcp_max_tw_buckets
程序中使用SO_LINGER,应用强制使用RST关闭。