当前位置: 首页 > news >正文

TCP头分析+面试题

一、测试程序

我们先用python来写两个测试脚本,非常简单,看代码:

服务端:

from socket import *

def accept():
    sock = socket(AF_INET, SOCK_STREAM, 0)
    sock.bind(("127.0.0.1", 5000))
    sock.listen(5)
    while True:
        pass
    
if __name__ == "__main__":
    accept()

客户端:

from socket import *

def connect():
    sock = socket(AF_INET, SOCK_STREAM, 0)
    sock.connect(("127.0.0.1", 5000))

if __name__ == "__main__":
    connect()

1)服务端只是简单的监听连接,什么事都不做,连关闭都没有

2)客户端只管连接服务端,什么事都不做,也没有关闭

3)这两个程序都将运行是在同一物理机器


二、TCP三次握手

我们先运行服务端,此时服务端没有任何通信数据,我们再运行客户端,由于发生了connect,此时就发生了TCP的三次握手,我们来看下握手的数据,这里我使用的工具是commview

上图显示了这三次握手的数据,可以看到,同一台机器上的回路通信,Src Mac 与 Dest Mac 显示的只是端口不一样,(前面4个字节是网卡地址,后两个字节是端口号),但网卡地址不是物理机器上的网卡地址,这是回路的Mac地址。Dest Port 是5000,这是我们监听的IP端口。Src Port是3877,这个是随机的IP端口。当客户端发生connect时,操作系统随机一个没有被使用过的IP端口供客户端使用。


我们来看下选中的第一行,具体的内容:

上图展示了第一次握手的具体数据,这是TCP/IP协议的头部信息。

面试题一:同一台机器上的网络通信,在数据包里,MAC地址是多少?是网卡实际MAC地址吗?

1、前6个字节,00 00 00 00 是目标网卡的地址, 00 02 是目标网开放的端口

2、7~12字节,00 00 00 00 是源网卡的地址,00 01是源网卡开放的端口

3、13~14字节,08 00是以太网类型,这里是IPV4网际协议,如果是IPV6则是86 DD,ARP 是08 06

以上14个字节,我们称为以太头,就是上图里红色部分

面试题一答案:不是实际地址,是00 00 00 00,是操作系统虚拟出来的网卡地址


面试题二:一个数据包在网络中,找不到目标机器,会发生什么事?会一直存在吗?

面试题三:TCP/IP协议,有地址和端口,请问,端口是谁的?TCP的,还是IP的?

4、第15个字节,45,其中4,表示IP协议版本号,即IPV4,5表示IP协议头部长度,(要注意的是,这个数据的单位是32位,也就是4个字节),所以这里的5其实表示的是20,就是说IP头有20个字节长。

5、第16字节,是区分服务,最常见的是IP电话

6、17~18字节,00 28,2 * 16 + 8 = 40个字节,这个表示整个TCP/IP协议的总长度,不包括以太头。

7、19~20字节,00 00 ,ID标识,表示这个数据包的ID,相同ID的数据包将被视为一个包,也就是说,当发生拆包时,用这个ID就能把包整合成一个正确的包。

8、21~22字节,00 00,标志(3位) + 帧位移(13位)。与上面的ID共同作用,相同的ID在整合成一个包时,帧位移标识这个帧应该放在包的哪个位置。标志表示后面是否还有数据帧。

9、第23字节,40,这个是生存时间,意思是,这个数据包在网络中的生存多久,如果没有被正确接收,当这个包存在时间超过这个生存时间时,这个包将被丢弃,这可以用来防止网络短路而造成数据包拥塞。

10、第24字节,06,这个是协议编号,告诉目标机器,我这个数据包的内容使用什么协议来承载。

11、25~26字节,7C CE,这个是checksum,校验和。有兴趣的童鞋可以网上参考一些checksum算法的文章。看看这个字段是怎么校验IP头是否正确。

12、27~30字节,7F 00 00 01是源IP地址,127.0.0.1

13、31~34字节,7F 00 00 01是目标IP地址127.0.0.1

以上20个字节,我们成为IP头。其IP地址的表示与以太头的表示顺序相反,以太头先目标MAC地址,再源MAC地址,IP头是先源IP地址,再目标IP地址。而且,IP头并不包括端口号。IP头有点复杂。但实际用到的不多。

面试题二答案:数据包存在时间超过生存时间时,会被丢弃,不会一直存在。

面试题三答案:端口是TCP的。


面试题四:TCP发送的序号与应答序号有什么关系?是一样的吗?

面试题五:如果我要让对方的QQ下线,该怎么做?

14、35~36字节,0F 25,这个是源端口号,0x0F25 = 3877

15、37~38字节,13 88,这个是目标端口号,0x1388 = 5000

16、39~42字节,00 00 00 00,这个是TCP顺序号,用于使TCP进行可靠传输。当发出一段报文时,序列号就+1

17、43~46字节,00 00 00 00,这个是TCP应答号,用于告诉目标机器,我这段报文,应答的是你发过来的哪一段顺序号报文。这个应答的编号,是顺序号+1。

18、47字节,50,这个表示TCP头部的长度,同样的,这里的5表示20字节,以32位为单位。

19、48字节,02,这个字节是TCP的6个标志位,也叫控制位。只使用后6位,02 = 0000 0010,各位的意义如下:

URG:1,紧急指针有效,0,紧急指针无效

ACK:1,确认号有效,我是应答包。0,确认号无效,我不是应答包

PSH:接收方应该尽快将这个包发送到应用层。

RST:重建连接,表示之前这个连接发生问题了,重新建立连接

SYN:发起一个连接

FIN:释放连接

20、49~50字节,40 00,窗口大小,用于流量控制,比如,发送端速度很快,接收端速度很慢,就没必要傻傻的一直快速发送。

21、51~52字节,00 00,TCP的checksum。

22、53~54字节,紧急指针。我不懂,这个我真不懂,我做了那么久得行为审计,从来没有关注过这个东东,我搞懂了再补上。。。。。

面试题四答案:应答序号是发送序号+1,不一样。

面试题五答案:向对方的机器发送一个FIN包


面试题六:为什么TCP协议是三次握手,不是两次,也不是四次?

我们再来看三次握手接下去的两次握手


验证序号:图中下划线红色部分,服务端首次发送,所有是00 00 00 00,服务端应答客户端序号00 00 00 00的数据,所以是00 00 00 01,图中蓝色部分。第48字节位12,即00010010,是ACK + SYN


验证发送:00 00 00 01, 00 00 00 01都是对的,flag为10 = 00010000 = ACK

面试题六答案:三次,可以解释为,双发都知道对方的存在。两次,只能是我发送的东西,对方能收到,但对方却不知道他发送的东西,我能不能收到。三次刚好,四次冗余


二、有数据的传输过程

先对程序进行改造,如下:

服务端:

from socket import *

def accept():
    sock = socket(AF_INET, SOCK_STREAM, 0)
    sock.bind(("127.0.0.1", 5000))
    sock.listen(5)
    while True:
        cltSock = sock.accept()
        print(cltSock)
        data = cltSock[0].recv(128)
        print(data)
        break
    
if __name__ == "__main__":
    accept()

客户端:

from socket import *

def connect():
    sock = socket(AF_INET, SOCK_STREAM, 0)
    sock.connect(("127.0.0.1", 5000))
    sock.send(str.encode("123"))

if __name__ == "__main__":
    connect()

面试题七:用户发送的数据,TCP/IP如何知道用户发送了多长的数据?
我们运行程序,然后看抓包,如下:


可以看到,多了一个数据包,这个数据包最后还有我们发送的数据“123”,看图中红线部分,它是17~18字节,表示TCP/IP协议总长度,2B = 2*16+11=43,减去IP头20, TCP头20,就能得出3个用户自己发送的数据。

面试题七答案:TCP/IP只记录了整个数据包的总长度,根据总长度,减去IP头和TCP头,得出用户发送的数据长度


三、结束会话

同样的,我们改造一下程序,如下:

服务端:

from socket import *

def accept():
    sock = socket(AF_INET, SOCK_STREAM, 0)
    sock.bind(("192.168.1.101", 5000))
    sock.listen(5)
    while True:
        cltSock = sock.accept()
        print(cltSock)
        data = cltSock[0].recv(128)
        print(data)
        break
    cltSock[0].close()
    
if __name__ == "__main__":
    accept()

客户端:

from socket import *

def connect():
    sock = socket(AF_INET, SOCK_STREAM, 0)
    sock.connect(("192.168.1.101", 5000))
    sock.send(str.encode("123"))
    sock.close()

if __name__ == "__main__":
    connect()

对TCP/IP稍微有了解的童鞋,都应该知道,这里会有四次握手断开的数据,如下图:


我们看到,在192.168.1.102这台主机发送了“123”这个数据之后,确实还有四个数据包,依次是


这个包含了一个FIN,和一个ACK


这个包含了一个ACK

这个包含了一个FIN和一个ACK


这个包含了一个ACK

至此,四次握手断开,就结束了。

使用commview的童鞋,可能捕捉不到4次握手断开,那是因为你用了loopback本地回路,改成用你自己的网卡,然后在局域网测试,就能看到四次握手断开了。如果是linux的朋友,就没这个烦恼了~~~


五、linux上的tcpdump捕捉结果

在linux上做此实验的同学,可以使用tcpdump看下,可以这样输入命令:

tcpdump src host 192.168.109.129 or dst host 192.168.109.129 and tcp port 5000

地址和端口,自己改改哈

得到的数据大概是这样的:


好了,就到这里结束吧,有疑问的童鞋,留言哈~~~

相关文章:

  • Maven--多模块依赖实例解析(五)
  • Python解决codeforces ---- 1
  • HDU 2493 Timer 数学(二分+积分)
  • linux printk函数学习
  • HDU 3262 Seat taking up is tough (模拟搜索)
  • 2014各大网络公司校招笔试算法题(收集并更新中)
  • erlang mnesia 数据库查询
  • HDU 3264 Open-air shopping malls (计算几何-圆相交面积)
  • 2014Microsoft 校招笔试真题(找工作的虾米们赶紧做题晒答案喽)
  • 黑马程序员_IO流基本操作(Writer,Reader)
  • aptana 插件离线下载方式
  • Eclipse安装aptana 插件的方法
  • VC写的双人版俄罗斯方块
  • 2014百度校招笔试题之动态链接库静态链接库详解
  • centos 安装与操作
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • Android 架构优化~MVP 架构改造
  • JavaScript HTML DOM
  • Java编程基础24——递归练习
  • KMP算法及优化
  • rc-form之最单纯情况
  • Transformer-XL: Unleashing the Potential of Attention Models
  • Vultr 教程目录
  • Wamp集成环境 添加PHP的新版本
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 服务器之间,相同帐号,实现免密钥登录
  • 和 || 运算
  • 简单实现一个textarea自适应高度
  • 盘点那些不知名却常用的 Git 操作
  • 小程序开发之路(一)
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 做一名精致的JavaScripter 01:JavaScript简介
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • $.ajax中的eval及dataType
  • (1)常见O(n^2)排序算法解析
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (8)STL算法之替换
  • (c语言)strcpy函数用法
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (rabbitmq的高级特性)消息可靠性
  • (二)PySpark3:SparkSQL编程
  • (推荐)叮当——中文语音对话机器人
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转) RFS+AutoItLibrary测试web对话框
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • **CI中自动类加载的用法总结
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考