一、整理文章起因
工作中一次和其他业务对接接口,在使用过程中出现了我这边请求对方接口,而对方说没有收到我的请求,并且该现象还在持续发生,于是我通过tcpdump进行抓包分析,抓包结果如下:
这次的抓包和标准的四次挥手断开连接有点区别,想着很多时候现在面试一般都会问这些基础的协议相关内容,三次握手四次断开连接,TCP,UDP等,所以也想通过这次复习,把很多遗漏地方补充一下
二、TCP报文格式
对上图重要字段说明:
Source Port: 源端口,16位
Destination Port:目的端口16位
Sequence Number:序列号,32位
Acknowledgment Number:确认序号,32位
Control Bits:
URG: 紧急指针有效
ACK: 确认序号有效
PSH: Push Function
RST: 复位TCP连接
SYN: 发起一个新连接
FIN: 没有更多的数据发送 ,释放一个tcp连接
注意:不要把确认序号和标志位中的ACK弄混了,Ack确认号是对发起方的Seq+1
关于TCP连接过程中不同连接状态的说明:
- LISTEN:侦听来自远方的TCP端口的连接请求.
- SYN-SENT:在发送连接请求后等待匹配的连接请求
- SYN-RECEIVED:在收到和发送一个连接请求后等待对方对连接请求的确认
- ESTABLISHED:代表一个打开的连接,可以接收数据
- FIN-WAIT-1:等待远程TCP连接中断请求,或先前的连接中断请求的确认
- FIN-WAIT-2:从远程TCP等待连接中断请求
- CLOSE-WAIT:等待从本地用户发来的连接中断请求
- CLOSING:等待远程TCP对连接中断的确认
- LAST-ACK:等待原来的发向远程TCP的连接中断请求的确认
- TIME-WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认
- CLOSED:没有任何连接状态
为了方便理解,写一个一个socket服务端和客户端,抓包分析内容,来看一个标准的tcp三次握手和四次挥手
服务端代码:
import socket,os server = socket.socket() server.bind(('0.0.0.0',6666)) server.listen() while True: conn,addr = server.accept() print("一个新的连接:",addr) try: while True: print("等待接收") data = conn.recv(1024) if not data: break print("recv data:",data) res = data.decode("utf-8").upper() conn.send(res.encode()) print("send done") except Exception as e: print(e) server.close()
客户端代码:
import socket,os client = socket.socket() client.connect(('192.168.188.106', 6666)) while True: cmd = input(">>:").strip() client.send(cmd.encode("utf-8")) cmd_res = client.recv(1024) print(cmd_res.decode()) client.close()
抓包对客户端和服务端的的通信过程进行分析,这是一个非常的标准的三次握手和四次挥手过程:
先看针对上图中的三次握手:
在看看四次挥手的整理
关于TCP断开连接的说明
从上面的图我们可以看到是客户端主动断开连接,那么我们站在客户端的服务端两方面
对于客户端来说:
- 发送FIN告诉服务端要关闭连接,并自己进入FIN-WAIT-1状态,这个时候就不再处理和发送应用层用户的数据
- 收到服务端对FIN的ACK后,客户端进入FIN-WAIT-2状态,这个时候依然可以接收服务端的数据,如果收不到对方的ACK会再次发送之前包含FIN在内的消息
- 收到服务端发送的FIN之后说明服务端也没有数据发送并关闭连接了,此时客户端发送ACK对服务端的FIN进行确认并进入TIME-WAIT,然后等待2MS连接关
对于服务端来说:
- 收到客户端发送的FIN,发送ACK对这个FIN消息进行确认,并进入到CLOSE-WAIT状态
- 服务单在发送FIN的之前,如果还有未发送的数据,可以继续发送,发送FIN之后进入LAST-ACK
- 等待客户端的ACK消息确认自己的FIN完成关闭,如果客户端没有确认会再次发送FIN
小结:
发送FIN之后的一端将不会再发送数据
被断开的一方收到FIN后,给对方发送ACK表示收到,并自己的状态更改为CLOS-WAIT,此时TCP连接处于半关闭状态。被断开的一方仍然可以发送数据