[tcp] 使用socket模拟分析tcp协议

栏目: 服务器 · 发布时间: 6年前

内容简介:写两段简单的python代码,然后来抓包分析tcp协议服务端IP:172.16.196.145客户端IP:172.16.196.142

写两段简单的 python 代码,然后来抓包分析tcp协议

服务端IP:172.16.196.145

客户端IP:172.16.196.142

TCP三次握手、四次挥手

server端代码

import socket

s = socket.socket()
s.bind(('172.16.196.145',60000))
s.listen(5)

while 1:
    conn, addr = s.accept()
    date = conn.recv(1024)
    if date == 'get':
        conn.send('200 ok')
    conn.close()
    print 'Connected by', addr, 'now closed'

client端代码

import socket
s = socket.socket()
s.connect(('172.16.196.145',60000))
s.send('get')
print s.recv(1024)
s.close()

tcpdump抓包

1 12:43:46.905723 IP 172.16.196.142.41334 > 172.16.196.145.60000: Flags [S], seq 3255498564, win 14600, options [mss 1460,sackOK,TS val 1412272238 ecr 0,nop,wscale 7], length 0
2 12:43:46.905751 IP 172.16.196.145.60000 > 172.16.196.142.41334: Flags [S.], seq 4195434198, ack 3255498565, win 14480, options [mss 1460,sackOK,TS val 1425611003 ecr 1412272238,nop,wscale 7], length 0
3 12:43:46.905987 IP 172.16.196.142.41334 > 172.16.196.145.60000: Flags [.], ack 4195434199, win 115, options [nop,nop,TS val 1412272238 ecr 1425611003], length 0
4 12:43:46.906031 IP 172.16.196.142.41334 > 172.16.196.145.60000: Flags [P.], seq 3255498565:3255498568, ack 4195434199, win 115, options [nop,nop,TS val 1412272238 ecr 1425611003], length 3
5 12:43:46.906041 IP 172.16.196.145.60000 > 172.16.196.142.41334: Flags [.], ack 3255498568, win 114, options [nop,nop,TS val 1425611003 ecr 1412272238], length 0
6 12:43:46.906265 IP 172.16.196.145.60000 > 172.16.196.142.41334: Flags [P.], seq 4195434199:4195434205, ack 3255498568, win 114, options [nop,nop,TS val 1425611003 ecr 1412272238], length 6
7 12:43:46.906305 IP 172.16.196.145.60000 > 172.16.196.142.41334: Flags [F.], seq 4195434205, ack 3255498568, win 114, options [nop,nop,TS val 1425611003 ecr 1412272238], length 0
8 12:43:46.906406 IP 172.16.196.142.41334 > 172.16.196.145.60000: Flags [.], ack 4195434205, win 115, options [nop,nop,TS val 1412272239 ecr 1425611003], length 0
9 12:43:46.906487 IP 172.16.196.142.41334 > 172.16.196.145.60000: Flags [F.], seq 3255498568, ack 4195434206, win 115, options [nop,nop,TS val 1412272239 ecr 1425611003], length 0
10 12:43:46.906500 IP 172.16.196.145.60000 > 172.16.196.142.41334: Flags [.], ack 3255498569, win 114, options [nop,nop,TS val 1425611004 ecr 1412272239], length 0

逐行分析

第一行: 客户端172.16.196.142,端口(后面用点表示)41336向服务端172.16.196.145.60000发起SYN主动请求,seq为3255498564

第二行: 服务端172.16.196.145.60000给客户端172.16.196.142.41336确认ACK ack为3255498564+1=3255498565,并同时也发起SYN同步

第三行: 客户端回复服务端的SYN确认

第四行: 客户端调用s.send('get'),发送数据,因此为P标记(PST)

第五行: 服务端回复客户端ACK确认标记

第六行: 服务端调用conn.send('200 ok')给客户端回复数据,为P标记(PST)

第七行: 服务端发送回复数据后,关闭连接,发起FIN主动关闭

第八行: 客户端回复服务端数据的确认ACK(ack=4195434205)

第九行: 客户端发送FIN关闭连接

第十行: 服务端发送客户端FIN的确认,由此,整个连接关闭

从分析来看,这是一个正常的三次握手建立连接之后传输数据,但是说好的四次挥手呢?

第七行、第九行、第十行,其实只有三次挥手

为什么是三次挥手

把上面最后断开连接的包放下来看

6 12:43:46.906265 IP 172.16.196.145.60000 > 172.16.196.142.41334: Flags [P.], seq 4195434199:4195434205, ack 3255498568, win 114, options [nop,nop,TS val 1425611003 ecr 1412272238], length 6
7 12:43:46.906305 IP 172.16.196.145.60000 > 172.16.196.142.41334: Flags [F.], seq 4195434205, ack 3255498568, win 114, options [nop,nop,TS val 1425611003 ecr 1412272238], length 0
8 12:43:46.906406 IP 172.16.196.142.41334 > 172.16.196.145.60000: Flags [.], ack 4195434205, win 115, options [nop,nop,TS val 1412272239 ecr 1425611003], length 0
9 12:43:46.906487 IP 172.16.196.142.41334 > 172.16.196.145.60000: Flags [F.], seq 3255498568, ack 4195434206, win 115, options [nop,nop,TS val 1412272239 ecr 1425611003], length 0
10 12:43:46.906500 IP 172.16.196.145.60000 > 172.16.196.142.41334: Flags [.], ack 3255498569, win 114, options [nop,nop,TS val 1425611004 ecr 1412272239], length 0

看看上面最后关闭tcp连接抓到的封包

为什么上面抓包只有三次挥手呢,因为服务端在conn.send('200 ok')后马上就调用cnn.close()发起关闭连接了,而客户端收到后还得调用s.recv(1024),还没有发收到数据包的确认就马上又收到了服务端的FIN,于是客户端先是回复了服务端[P.]的ACK确认,然后此时客户端已经知道了服务端要关闭连接了,所以干脆合并FIN和ACK回复一个包,省掉一步,减少通信

抓到正确的四次挥手

既然知道是因为服务端太快的关闭了连接,因此修改服务端代码

import socket
import time

s = socket.socket()
s.bind(('172.16.196.145',60000))
s.listen(5)

while 1:
    conn, addr = s.accept()
    date = conn.recv(1024)
    if date == 'get':
        conn.send('200 ok')
        time.sleep(0.1) #暂停0.1秒后关闭连接
    conn.close()
    print 'Connected by',addr,'now closed'

我们暂停1秒后关闭连接,再抓包

1 20:01:49.251026 IP 172.16.196.142.41424 > 172.16.196.145.60000: Flags [S], seq 3935290883, win 14600, options [mss 1460,sackOK,TS val 1524954581 ecr 0,nop,wscale 7], length 0
2 20:01:49.251069 IP 172.16.196.145.60000 > 172.16.196.142.41424: Flags [S.], seq 3178165011, ack 3935290884, win 14480, options [mss 1460,sackOK,TS val 1538293348 ecr 1524954581,nop,wscale 7], length 0
3 20:01:49.251291 IP 172.16.196.142.41424 > 172.16.196.145.60000: Flags [.], ack 3178165012, win 115, options [nop,nop,TS val 1524954581 ecr 1538293348], length 0
4 20:01:49.251334 IP 172.16.196.142.41424 > 172.16.196.145.60000: Flags [P.], seq 3935290884:3935290887, ack 3178165012, win 115, options [nop,nop,TS val 1524954582 ecr 1538293348], length 3
5 20:01:49.251358 IP 172.16.196.145.60000 > 172.16.196.142.41424: Flags [.], ack 3935290887, win 114, options [nop,nop,TS val 1538293349 ecr 1524954582], length 0
6 20:01:49.251544 IP 172.16.196.145.60000 > 172.16.196.142.41424: Flags [P.], seq 3178165012:3178165018, ack 3935290887, win 114, options [nop,nop,TS val 1538293349 ecr 1524954582], length 6
7 20:01:49.251663 IP 172.16.196.142.41424 > 172.16.196.145.60000: Flags [.], ack 3178165018, win 115, options [nop,nop,TS val 1524954582 ecr 1538293349], length 0
8 20:01:49.251781 IP 172.16.196.142.41424 > 172.16.196.145.60000: Flags [F.], seq 3935290887, ack 3178165018, win 115, options [nop,nop,TS val 1524954582 ecr 1538293349], length 0
9 20:01:49.291441 IP 172.16.196.145.60000 > 172.16.196.142.41424: Flags [.], ack 3935290888, win 114, options [nop,nop,TS val 1538293389 ecr 1524954582], length 0
10 20:01:49.351812 IP 172.16.196.145.60000 > 172.16.196.142.41424: Flags [F.], seq 3178165018, ack 3935290888, win 114, options [nop,nop,TS val 1538293449 ecr 1524954582], length 0
11 20:01:49.352041 IP 172.16.196.142.41424 > 172.16.196.145.60000: Flags [.], ack 3178165019, win 115, options [nop,nop,TS val 1524954682 ecr 1538293449], length 0

6 服务端调用conn.send('200 ok'),seq=3178165012:3178165018

7 客户端收到封包的确认,ack=3178165018

8 此时发现跟之前不一样了,由于服务端暂停了0.1秒,因此主动关闭发送FIN标记的变成了客户端(172.16.196.142),seq:3935290887

9 服务端回复客户端的FIN确认ACK,ack:3935290888

10 服务端发起FIN关闭,seq:3178165018

11 行客户端回复服务端的FIN确认ACK,ack:3178165019

因此以上抓包抓到了TCP完整的四次挥手

CLOSING状态的tcpdump包

由于CLOSING状态是两边同时发FIN,而且还要在收到对方的ACK前收到FIN,因此代码很难实现,我倒是在web上面很容易就抓到了这种封包

1 19:40:34.831216 IP 10.29.64.142.443 > 10.25.137.230.46556: Flags [F.], seq 3633446994, ack 1764274713, win 131, length 0
2 19:40:34.832085 IP 10.25.137.230.46556 > 10.29.64.142.443: Flags [F.], seq 1764274713, ack 3633446994, win 480, length 0
3 19:40:34.832107 IP 10.29.64.142.443 > 10.25.137.230.46556: Flags [.], ack 1764274714, win 131, length 0
4 19:40:34.832395 IP 10.25.137.230.46556 > 10.29.64.142.443: Flags [.], ack 3633446995, win 480, length 0

1 10.29.64.142 发起了FIN,seq: 3633446994

2 10.25.137.230 发起了FIN,seq: 1764274713

3 10.29.64.142 发送确认ACK,ack: 1764274714

4 10.25.137.230 发送确认ACK,ack: 3633446995

这种封包就是同时发FIN,没有先收到ACK,而是收到对方的FIN,双方进入CLOSING状态的封包,不过随着对方很快发送ACK,因此双方进入TIME_WAIT状态


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learning jQuery

Learning jQuery

Jonathan Chaffer、Karl Swedberg / Packt Publishing / 2007-7-7 / GBP 24.99

jQuery is a powerful JavaScript library that can enhance your websites regardless of your background. In this book, creators of the popular jQuery learning resource, learningquery.com, share the......一起来看看 《Learning jQuery》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具