资讯专栏INFORMATION COLUMN

[tcp] 小段socket代码模拟分析tcp协议

testbird / 955人阅读

摘要:写两段简单的代码,然后来抓包分析协议服务端客户端三次握手四次挥手端代码端代码抓包逐行分析第一行客户端,端口向服务端端口发起主动请求,第二行服务端给客户端确认为,并同时也发起同步第三行客户端回复服务端的确认,三次握手建立连接第四行客户端调用,

写两段简单的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),seq:3255498565:3255498568
第五行: 服务端回复客户端ACK确认标记,ack:3255498568
第六行: 服务端调用conn.send("200 ok")给客户端回复数据,为P标记(PST),seq:4195434199:4195434205
第七行: 服务端发送回复数据后,关闭连接,发起FIN主动关闭,seq:4195434205
第八行: 客户端回复服务端数据(第六行)的确认ACK,ack:4195434205
第九行: 客户端发送FIN关闭连接,seq:3255498568 ack:4195434206
第十行: 服务端发送客户端FIN的确认,由此,整个连接关闭 ack:3255498569

从分析来看,这是一个正常的三次握手建立连接之后传输数据,但是说好的四次挥手呢?
第七行、第九行、第十行,其实只有三次挥手

为什么是三次挥手

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

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状态

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/45089.html

相关文章

  • 通过wireshark抓包来学习TCP HTTP网络协议

    摘要:所以得换一种思路来学习通过敲代码来学习,通过抓包工具来分析网络,抓包神器首推。本文是自己学习过程的记录和总结。这里是用写的,最近在学习。向指定端口发送连接请求,连接后发送一个并收到断开连接并退出。 很多招聘需求上都会要求熟悉TCP/IP协议、socket编程之类的,可见这一块是对于web编程是非常重要的。作为一个野生程序员对这块没什么概念,于是便找来一些书籍想来补补。很多关于协议的大部...

    spacewander 评论0 收藏0
  • Socket 编程实战

    摘要:本文原发于个人博客在英文中的含义为连接两个物品的凹槽,像,意为眼窝,此外还有插座的意思。协议,所是用的传输协议,目前有三种。,也称为无连接的,使用协议。当函数返回时,意味着对端已经关闭。 本文原发于个人博客 Socket 在英文中的含义为(连接两个物品的)凹槽,像the eye socket,意为眼窝,此外还有插座的意思。在计算机科学中,socket 通常是指一个连接的两个端点,这里的...

    TNFE 评论0 收藏0
  • 走进 mTCP

    摘要:互斥上锁引起的开销互斥上锁是多核平台性能的第一杀手。其次,线程间对文件描述符空间的互斥访问也会造成性能下降。介绍作为一种用户态协议栈库的实现,其在架构如下图所示以函数库的形式链接到应用进程,底层使用其他用户态的库。 mTCP 是一款面向多核系统的用户态网络协议栈 内核态协议栈的缺陷 互联网的发展,使得用户对网络应用的性能需求越来越高。人们不断挖掘CPU处理能力加强,添加核的数量,但这...

    李涛 评论0 收藏0
  • Netty 源码分析之 一 揭开 Bootstrap 神秘的红盖头 (客户端)

    摘要:目录源码分析之番外篇的前生今世的前生今世之一简介的前生今世之二小结的前生今世之三详解的前生今世之四详解源码分析之零磨刀不误砍柴工源码分析环境搭建源码分析之一揭开神秘的红盖头源码分析之一揭开神秘的红盖头客户端源码分析之一揭开神秘的红盖头服务器 目录 Netty 源码分析之 番外篇 Java NIO 的前生今世 Java NIO 的前生今世 之一 简介 Java NIO 的前生今世 ...

    zhaot 评论0 收藏0
  • #yyds干货盘点#Python之TCP UDP

    摘要:获取华文宋体套接字华文宋体获取华文宋体套接字华文宋体由于华文宋体模块中有太多的属性。我们在这里破例使用了华文宋体语句。 一、客户端/服务器架构硬件C/S架构(打印机)软件C/S架构(web服务)server端要求:力求一直提供服务要绑定一个唯一的地址,客户端可以明确的找到二、基于tcp协议的简单套接字Socket是应用层与...

    番茄西红柿 评论0 收藏2637

发表评论

0条评论

最新活动
阅读需要支付1元查看
<