前段时间在忙一个机器人通信的项目,其中用到一个重要的协议族就是TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/国际互联协议),我一直觉得TCP/IP协议设计的真的是太巧妙了,可以说是这个星球上最伟大的通信协议,小到微信的即时通讯,大到航空航天等自动控制工业领域,它的身影无处不在,正是有了TCP/IP,我们发送的每一条互联网信息才能安全无损地到达对方(比如你有没有想过你身在北京,打开微信给身在上海的朋友发个祝福短语这期间你的信息究竟经历了什么,为什么能准确无误地到达),一个TCP/IP协议,半部计算机网络史,所以我觉得每一位计算机从业者或者计算机相关从业者都应该花点时间研究一下TCP/IP协议。

大道至简,今天我们使用一个抓包工具Wireshark来抓个数据包,然后对其抽丝剥茧,逐步来揭开TCP/IP的神秘面纱吧!

1997年12月,美国总统布什为TCP/IP之父罗伯特·卡恩(中间)颁发的美国国家技术勋章。

因特网起因于美苏争霸期间美国国防部准备研究的一种分散的指挥系统,由无数节点构成,当若干节点被摧毁后,仍然能够通过其他节点互相通信。它是一种拓扑结构,你从北京发送的信息到上海可以走多种路径,TCP/IP的神奇之处就在于它能够让你的信息准确无误地到达。

何为「协议」(protocol)?「协」的本意是指多人合作,而后面的那个「议」在古汉语中的意思是一种文体,那么合起来就是多人合作共同遵守的一种文体,后来引申为双方共同约定遵守的一种规则。生活中的协议有很多,比如你刚毕业的时候签订的三方协议,还有租房的时候有租赁协议,再说远一点,秦始皇统一中国后为了方便全国的交流,制定了「车同轨,书同文」的规则,这应该是中国历史上最早的国家标准了吧,这也是一种协议,还有,你看谍战片,双方传递信息的时候都有口号,这都是事先约定好的,都是一种协议,双方必须遵守。

有了协议,就大大方便了我们的交流,比如我们在打电话的时候一般都会说声“喂,你好”,等对方确认应答后才说明双方确实都通了,然后开始正式通话,而对于TCP来说也是这样的,TCP在建立连接的过程中要进行三次握手,双方完全确认无误后才会互相通信:

三次握手示意图

带着这张图片的信息,让我们展开抓包之旅吧!

抓包前的准备工作

第一步,首先我们下载一个抓包软件Wireshark,这个软件百度一下,网上很多,直接下载即可;

第二步,然后我们在自己的电脑上ping一下百度的域名:www.baidu.com,这样就能知道百度服务器的IP地址,当然百度在全国肯定不止一台服务器,所以每个人ping出的地址可能不一样,比如我ping出的是180.101.49.12 。

第三步,我们打开抓包软件,在选项里面选择你的网络接口,然后点击开始,Wireshark就开始帮你抓包了;

第四步,我们打开浏览器,输入刚才ping到的百度服务器的IP地址,输入地址栏按回车,这样就打开百度首页了,其实我们平常输入的网址也是经过DNS服务器解析后转化成IP进行访问的。没错,我们就是通过访问一个百度网址来抓取在键入回车后双方的报文信息的。

第五步,我们在抓包软件搜索框内输入ip.addr == 180.101.49.12 and tcp指令来帮助我们过滤掉多余的信息:

好了,可见我们抓取了很多条信息,但是我们只需要前三条即可,因为前三条就是双方建立连接(三次握手)过程中互相传递的报文信息。

在分析这三条报文前,我们回忆一下TCP/IP每层网络模型中的报文结构:

每层模型对自己的数据加包头后发给下一层:

这是微信发送消息的模型(所有TCP/IP协议都是这样),当然微信肯定不是端对端直接传送到另一个手机,而是先传送到腾讯服务器,再转推给对方,不过原理是一样的。

可见每层都是胶囊化的数据,经过加工后(一般都是加上报头)然后传送给下一层,最终由物理层的传送介质(比如光纤)传送给对方电脑,对方收到后再反过来解析,剥开每一层的报头,最终露出数据部分,这才是我们真实要的数据。所以,我们抓到的包都是在最下面的以太网帧,包含帧头、帧尾、IP头部、TCP头部的数据包,所以我们必须先从最后一层分析。

数据链路层

在数据链路层我们收到的以太网帧头部结构如下(下面这张图片为了描述方便,宽度我与位长度我没有按照比例来画):

简要解释一下几个字段的含义:

前导同步码

提醒接收系统即将有帧到来,七次写入 10101010;

帧开始分界符

表示帧的发送从下一个数据报正式开始,二进制数序列为 10101011 ;

帧的长度 / 类型

内容为帧长度(单位为字节)或者交给上层协议的信息。具体是哪种内容,取决于以太网的种类。

我们先来看第一次握手的数据

第一个红框b0 95 8e 0b 15 38代表目标MAC地址,也就是百度服务器的网卡地址;

第二个红框10 63 c8 ffffff代表源MAC地址,也就是我自己电脑的网卡地址,后三个字节 ff ff ff 是我虚拟的,包括上面图片中我也打了马赛克,为什么,因我怕黑客知道我的网卡地址后攻击我的电脑;

第三个红框08 00代表的是 IPv4 协议。

等等,你可能会问,帧头的前导同步码与帧开始分界符怎么没有显示呢?

这是因为在物理层上网卡要先去掉前导同步码和帧开始定界符,然后对帧进行CRC检验,如果帧校验和错,就丢弃此帧。如果校验和正确,就判断帧的目的硬件地址是否符合自己的接收条件(目的地址是自己的物理硬件地址、广播地址、可接收的多播硬件地址等),如果符合,就将帧交“设备驱动程序”做进一步处理。这时我们的抓包软件才能抓到数据,因此,抓包软件抓到的是去掉前导同步码、帧开始分界符、FCS之外的数据。

网络层

我们先来看网络层,也就是 IP 层的头部结构:

先来大致解释一下每个字段的含义:

版本(version)

如果是 IPv4 则填入 4 ,如果是 IPv6(当然报头结构跟 IPv4 结构不一样)则填入6。

头长度(Header Length)

IP 报头的大小,头部长度是指IP报头的总长度,因为有Option可选部分,通常为20字节,范围在20--60字节,注意,该字段单位为32位字(1个32位字为4字节),因此当ip报头长度为1111(15)时是最大60(15*4)字节,一定要注意,这个字段的单位比较特殊,容易弄错。

服务类型(Differentiated Services Field)

显示发送信息时的优先情况。

数据包总长度(Total Length)

IP报头与数据的整体大小,表示此IP报头和数据的之和的总长度。总长度16位,一个数据最大长度65535字节;链路只允许1500字节,超过的话需要进行MTU分片。一个数据包由IP报头和数据两部分组成,而IP报头为20---60字节,所以不会有一个数据包里纯数据超过1480字节。

标识符(Identification)

将分割后的 IP 数据包复原时使用的值,与标记字段和偏移字段用于IP报文分片。原始报文大小超过MTU(<1480B)就必须将原始数据进行分片,每个分片小于MTU,对同一原始文件被分片的报文打上相同的标记,也用来判断流量是否来于同一主机。IP软件在存储器中维持一个计数器没生产一个数据包,计数器就加1,并赋予标识字段。数据报文进行分片处理后每个分片的标识值都与原数据包的标识值相同,接收端具有同标识值的分片就能最终正确重组为原数据。

旗标(Flags)

关于数据包分割的信息:

第一位没有被使用;

第二位不分片(DF),当DF位置为1时表示路由器不能对报文进行分片处理;第三位多分片(MF),当路由器对报文进行分片时,除了最后一个分片的MF位设置为0外,其他所有分片MF位置为1,以便接收者直到收到MF位为0的分片为止。

例如,如果数据包被分成两段,那么第一个flags就是101,第二个flags就是100.

分片偏移(Fragmentation offset)

被分割的数据的顺序,标识分片在分组中的位置。

生存时间(Time to live, TTL)

允许经过最大的路由器数量,即数据包能传多少跳。不同操作系统TTL的默认最大值会有所不同,目的是防止路由成环时IP数据被无限转发,每经过一个路由器TTL值减1,TTL为0时丢弃该分组。

协议(Protocol)

上一级协议,标识数据携带的数据是何种协议,标识传输层地址或协议号,如1代表ICMP,6代表TCP,17代表UDP.

包头校验和(Header checksum)

确认 IP 包头是否损坏的数值,用于校验检查IP报头是否有出入。

选项(Option)

可选字段(0--40B)Option字段很少使用,用于控制,转发要求,测试等。

网络层的信息比较多,我们只捡几个重要的信息来说一下:

第二行的c0 a800 65转化成十进制就是192.168.0.101这是我电脑的 IP ,注意这里是局域网 IP, 后面的b465 310c转化成十进制就是180.101.49.12,是目标IP,也就是百度服务器的 IP。

传输层

传输层的功能是保证数据可靠地从发送结点发送到目标结点,我们看一下它的头部结构,已经能够看到携带的握手信息了。

序列号(Sequence Number)

表示在所有的数据中,此数据是第几个

确认应答号(AcknowledgmentNumber)

表示即将接收的下一个数据是第几个

我们再看抓到的包数据,再剥一层,把 IP 头去掉,先看第一次握手:

我们可以看到:第一次握手的过程中,客户端随机生成了一个序列号,数值挺大的,然后将状态控制码中的 SYN 置为1,发送给服务端。

第二次握手:

在服务端收到客户端的报文后,服务端再给客户端一个应答,由于是服务端给客户端打招呼,因此端口号互换一下,这边服务端也随机生成一个序列号,同时将第一次握手收到客户端的序列号加1,作为确认序列号发送过去,同时将状态控制码的ACK与SYN置为1,发送给客户端。

第三次握手:

第三次握手是客户端在收到服务端的回应后,客户端再一次回应。可以看到,序列号就是第二次握手服务端发来的确认应答序列号,而第三次握手客户端的确认序列号就是第二次握手服务端发来的确认序列号加1。

这样,三次握手就完成,双方建立连接,可以互相通信了。

好了,以上就是今天的全部内容了,其实三次握手只是TCP里面的冰山一角,真正传输过程中还涉及到非常多的知识,比如超时重传、校验、窗口机制等等,不过今天先说到这里吧,基础薄弱的同学可以先消化一下,后面的知识等有时间再给大家说。

标签: