TCPSocket编程分析
实验通过两台WMware中的虚拟机中运行的Server和Client互相通信,然后用wireshark抓取报文,从而对TCP报文进行分析
代码
代码部分十分简短,两端通过Socket建立连接后,服务器等待客户端发来信息,收到客户端发来的信息后将其转换为对应的小写字母表示,然后回复给客户端。客户端收到来自服务器的回复后就主动断开连接。
# TCPServer.py
from socket import *
serverPort = 13000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
serverSocket.listen(1)
print('The server is ready to receive')
while True:
connectionSocket, addr = serverSocket.accept()
sentence = connectionSocket.recv(1024).decode()
capitalizedSentence = sentence.upper()
connectionSocket.send("server callback:".encode()+capitalizedSentence.encode())
connectionSocket.close()
# TCPClient.py
from socket import *
serverName = '192.168.124.17' # 服务器IP
serverPort = 13000
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName, serverPort))
sentence = input('Input lowercase sentence:')
clientSocket.send(sentence.encode())
modifiedSentence = clientSocket.recv(1024)
print('From Server: ', modifiedSentence.decode())
clientSocket.close()
运行
- 在虚拟机1(Ubuntu)运行Server和Wireshark,在虚拟机2(CentOS)运行Client。
- 客户端发送信息给服务器
- 客户端收到来自服务器的回信
- 断开连接。
抓包分析:
利用Wireshark对Server端的ens33网卡进行抓包,结果如下:
过滤条件:tcp.port==13000
通过wireshark生成流量图的功能,生成TCP的流量图如下:
分析该图片可以看出,服务器和客户端一共进行了十次TCP的交流,其中:前三次是为了建立连接的握手过程,最后四次是为了断开连接的挥手过程,中间三次是数据交互的过程。
TCP的FLAGS字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG.其中,对于我们日常的分析有用的就是前面的五个字段。它们的含义是:
- SYN表示建立连接,如果只是单个的一个SYN,它表示的只是建立连接
- FIN表示关闭连接,
- ACK表示响应。可能与SYN,FIN等同时使用的,比如SYN和ACK可能同时为1,它表示的就是建立连接之后的响应,
- PSH表示有 DATA数据传输,
- RST表示连接重置。
三次握手:
- 客户端先向服务端发送SYN包(Socket状态从closed变成SYN-SEND)。
- 服务端收到SYN包后(Socket状态从LISTEN变成SYN-RECV),向客户端发送针对此SYN包的SYN/ACK包,以确认收到了这个SYN包。
- 客户端收到此SYN/ACK包后(Socket状态由SYN-RECV变成Established),再向服务器发送SYN/ACK包
- 服务器收到ACK包之后就可以通信了。
四次挥手
- 客户端向服务器发送FIN数据包,表示要断开连接,Socket状态从Established变成FIN_WAIT_1。
- 服务器收到FIN数据包后,向客户端发送ACK包,表示准备断开,从Established变成closed_wait。
- 客户端收到ACK包,从FIN-wait-1变成FIN-WAit_2,等待服务器发送确认断开的包。
- 服务器发送FIN包,确认断开连接,变成LAST-ACK。
- 客户端收到FIN包后,发送ACK包,变成TIME-Wait,等待2个报文生成时间后,变成closed状态。
- 服务器收到ACK包后,变成Closed。
数据交互过程:
Seq: (sequence number)表示的是发送方这边,这个packet的数据部分的第一位"应该"在整个data stream中所在的位置。
注意,SYN/FIN的传输虽然没有data,但是会让下一次传输的seq增加一,但是ACK的传输,不会让下一次的传输sqp加一。
Ack: (acknowledge number)表示的是期望的对方(接收方)的下一次sequence number是多少。
为了保证数据准确到达,目标机器在收到数据包(包括SYN包、FIN包、普通数据包等)包后必须立即回传ACK包,这样发送方才能确认数据传输成功。Ack号 = Seq号 + 收到的字节数 + 1
三次握手
- 第一条SYN报文是TCP的第一次握手,故Seq Ack都为0
- 第二条SYN/ACK报文是TCP的第二次握手,Seq = 0,Ack = Seq+data+1 = 1
- 第三条ACK报文是TCP的第三次握手,Seq = 0+1 =1(发送SYN会让seq+1),Ack = Seq+data+1 = 1
数据交互
- 第四条PSH/ACK报文是客户端给服务器发送的数据,Seq =1,Ack = Seq+data+1 = 1
- 第五条ACK报文是服务器回复客户端的报文,Seq = 0+1 =1(发送SYN会让seq+1),Ack = Seq+data+1 = 15
- 第六条ACK是服务器给客户端发送的数据报文,Seq = 0+1 =1,Ack = 15
四次挥手
- 第七条FIN/ACK是服务器发起的第一次挥手,Seq = 1+30(发出的数据) =31,Ack = 15
- 第八条ACK是客户端回应的第二次挥手,Seq = 1+14(发出的数据) = 15,Ack =1+30(收到的数据)= 31
- 第七条FIN/ACK是客户端回应的第三次挥手,Seq = 15,Ack =31 + 0 +1= 32
- 第七条ACK是服务器发出的第四次挥手,Seq = 31 + 1(FIN)=32,Ack =15 + 0 +1= 16