×

TCP/IP 协议及数据格式

96
Super超人
2018.01.20 11:53* 字数 9103

读懂了TCP/IP协议,也就基本了解的网络通信原理。本文是参照研究生教材《网络安全原理与应用》里面的内容加上自己实际抓包数据分析结合而来,去年第一次看这本书,上面读起来枯燥难懂,读一天也看不到一页,感觉说的又大又空,经过一年的网络编程实战之后再回过头来看这本书里面关于TCP/IP部分的讲解,解开了我很多的疑问。但是书中也只是讲个大概理论,有的地方描述不当或者不准确,网络上也充斥很杂的一些文章,有好的也有坏的,让人看起来眼花。下面来结合书上的讲解和我自己的理解来聊聊常见的TCP/IP协议。

目录

1、TCP/IP 协议体系
2、IP协议
2.1 概念
2.2 功能
2.3 IP协议数据报的头

2.3.1 IP协议头部格式
2.3.2 IP协议头部数据

2.4 IP地址分类

2.4.1 IP地址分类
2.4.2 子网掩码、超网

3、TCP协议
3.1 概念
3.2 TCP协议数据报的头

3.2.1 TCP协议头部格式
3.2.2 TCP报头可选项字段
3.2 .3 TCP协议头部数据

3.3 TCP通信数据交互细节和实践

3.3.1 TCP建立连接的三次握手抓包数据部分
3.3.2 TCP数据交互抓包数据部分
3.3.3 TCP断开连接的四次握手抓包数据部分

4、UDP协议
4.1 UDP协议数据报头

4.1.1 UDP协议头部格式
4.1.2 UDP协议头部数据

5、结语

1、TCP/IP 协议体系

为了减少网络设计的复杂性,大多数网络都采用了分层结构。不同的网络,层的数量、名字、内容和功能都不尽相同。相同网络中,一台机器上的第N层与另一台机器上的第N层利用第N层协议进行通信,协议基本上是双方关于如何进行通信所达成的一致。
TCP/IP参考模型就是一个符合上面描述的网络体系结构。他是依据他的两个主要协议-TCP和IP而命名的。这一网络细分一般是七层:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层,有关于这七层协议想要了解的可以看下百度百科讲解的网络七层协议,这里就不做过多的废话,重点在下面。

2、IP协议

2.1 概念

IP协议用于连接多个分组交换网,他提供在具有固定地址长度的主机之间传送数据报,以及根据各个数据包大小的不同,在需要时进行分段和重组大数据报的功能。IP协议仅限于将数据从源端传送到目的端,而不提供可靠的传输服务。在传送出错时,IP协议通过互联网控制消息协议(ICMP, Internet Control Message Protocol)报告。

2.2 功能

IP协议最基本的两个功能:寻址和分段

寻址:IP协议根据数据报头中所包含的目的地址将数据报传输到目的端,传送过程中对道路的选择称为路由
分段:当一些网络只能传送小数据报时,IP协议将数据报分段并在报头里面注明。数据包也可以被标记为“不可分段”,如果一个数据报被如此标记,那么在任何情况下都不准对他进行分段,如果因此到不了目的地,那么数据包就会在中途被丢弃。

2.3 IP协议数据报的头:

2.3.1 IP协议头部格式
IP协议数据报的头格式.jpg
  • 版本:记录数据报属于哪个版本的协议,例如可以用此区分出IPv4和IPv6,这个字段可以使得在不同版本间传递数据变得可行。

  • 头部长:标明IP协议报头有多长,其单位是32bit即4个字节,其最小值为5(5 x 4 = 20 byte,这个长度是除去可选项的长度),从上图中看出,其规定头部长为 4 bit,所以最大值为 15, 15 x 4 = 60 byte 可以算出可选项长度最大为40个字节(即 60 byte - 20 byte = 40 byte)

  • 服务类型:用来指示当数据报在一个特定网络中传输时对实际服务质量的要求是什么,服务类型字段从左到右由一个3位的优先顺序字段、三个标志位(D、T、R)和两个保留位组成。优先顺序字段用于标志该数据报的优先级,D、T、R三个标志位分别代表是否对低延迟(Delay)、高吞吐量(Throughput)、高可靠性(Reliability)有要求,不过实际上,现在的路由器都忽略服务类型这个字段。

  • 总长:是指整个数据报的长度,包括头部和数据部分,单位是 1 个字节,从图上可以看出,规定总长位数为16bit,能存储最大数据为65535个字节的数据报。如长的数据报对大部分主机和网络来说是不现实的。所有主机必须能够接收长达576个字节的数据报(不管他们是以整个数据报到达还是以分片到达),源端主机在确认目的地址能够接收大数据报的情况下才发送大于576字节的数据报。

  • 标识:该标识由发送者设定值,主要为了目的主机组装分段时判断新到的报文分段属于哪个分组,所有属于同一分组的报文分段都包含相同的标识。

  • 标记:长度为3bit,从前到后分别是保留位不可分段位(DF, Don't Fragment)和分段位(MF,More Fragment)。
    保留为始终为 0
    DF位为 1 时表示该分组不能被分段
    MF位为 1 时表示后面还有该分组的分段,在有分段的情况下,除了最后一个分段该位为 0 外,其他分段该位都为 1

  • 分段偏移:标记该分段在数据报的位置,单位是8个字节,第一个分段的偏移是 0

  • 生命期:用来限制分组生命周期的计数器,单位是秒,该字段长度为 8bit ,说明存储的最大数值是 255 ,在实际的应用过程中是以经过的节点计数的,每经过一个节点计数减 1 ,计数减到 0 时,分组要被丢弃。

  • 协议:指明IP层所封装的上层协议类型,如ICMP -> 1、IGMP -> 2 、TCP -> 6、UDP -> 17、EIGRP -> 88 、OSPF -> 89等

  • 头部效验和:只对头部进行效验,由于头部的一些字段始终在变化(例如:生命期字段),头部效验和在每个节点都得重新进行计算。

  • 源地址:发送报文段的IP地址

  • 目的地址:接收报文段的IP地址

  • 可选项:可选项对于主机和网关的IP模块来说都是必须实现的,可选是指它们在特定数据报中是否出现是可选的,而不是指他们的实现,每个可选项都以 1 个字节表明它的类型。其长度从1~40个字节之间不固定,主要取决于设置的可选项数目,最终数据长度不够32位的倍数要填充 0 补齐,主要是为了让报头长度是32位的整数倍,一般正常的IP报文头部都是没有可选项的。
    目前已定义的可选项有 5 个,分别是安全性(指明数据报的机密程度)、严格路由选择(后面给出所规定的完全路由)、宽松路由选择(后面给出必须要经过的路由)、记录路由(记录下所经路由器附上其IP地址)、时间戳(要求所经路由器都附上其IP地址和时间标记)。

2.3.2 IP协议头部数据

下面是我用抓包工具抓到的一个TCP断开的四次握手,其他的咱不管,先看第一次发送FIN类型数据包的IP报头部分

IP数据报.png

最下面的是数据,去掉以前面太网首部的14个字节开始是IP数据报头部分,下面我们对着上面的格式来解析下

先单独把IP报头数据粘贴下来

//字节为单位 Hex+ASCII方式显示
45 00 00 28 a2 ad 40 00 39 06 0f 71 b7 83 87 91 0a 16 46 87

//二进制 bit流显示为
01000101 00000000 00000000 00101000 
10100010 10101101 01000000 00000000 
00111001 00000110 00001111 01110001 
10110111 10000011 10000111 10010001 
00001010 00010110 01000110 10000111
字段 位置 含义
版本 0-3 0100 属于IPv4版本
头部长 4-7 0101 表示头部长度为20个字节(5 x 4 byte = 20 byte)
服务类型 8-31 00000000 ....
总长 32-47 00000000 00101000 IP数据报总长(不包括以太网首部) 为 40 个字节(40 x 1 byte = 40 byte)
标识 48 - 50 010 保留位为 0 , 不可分段数据报
分段偏移 51 - 63 00000 00000000 数据偏移为0,数据报属于分组的第一个分段(其实这个数据包是不允许分段的,这里只是一个理论解释)
生命期 64 - 71 00111001 生命期值是57,理论解释是还可以经过57个节点
协议 72 - 79 00000110 值为6,表示上层为TCP协议
头部效验和 80 - 95 00001111 01110001 ....
源地址 96 - 127 10110111 10000011 10000111 10010001 因为IP地址在网络中传播是用网络排序(大端)表示,所以直接按顺序解析,16进制表示:b7.83.87.91,转换成十进制表示为:183.131.135.145
目的地址 128 - 159 00001010 00010110 01000110 10000111 十进制点形式表示为:10.22.70.135
可选项 ~ ~ 没有可选项

2.4 IP地址分类

2.4.1 IP地址分类

IP地址包含网络号和主机号两部分,网络号代表一个子网络,主机号则表示该子网络下某一台具体的主机标号,IP地址根据功能和用途的不同可以划分为五类。
A 类地址:1 . 0 . 0 . 0 ~ 126 . 255 . 255 . 255,前 8 位为网络号,后 24 位为主机号
B 类地址:128 . 0 . 0 .0 ~ 191 . 255 . 255 . 255,前16位为主机号,后16位为主机号
C 类地址:192 . 0 . 0 . 0 ~ 223 . 255 . 255 . 255,前24位为网络号,后8位为主机号
D 类地址:224 . 0 . 0 .0 ~ 239 . 255 . 255 . 255
E 类地址:240 . 0 . 0 . 0 ~ 254 . 255 . 255 . 255

A、B、C三类地址是根据网络规模大小来分配给用户的,例如A类地址有24位的主机号,同一个网络下,一个 A 类地址可以容纳 2^24 - 2 = 16777213 台主机,但是A类地址一共只能分配 126 个网络(这里只是做一个理论上的运算,并不代表实际分配情况),所以这类地址一般分配给那些为数不多的大网络。D类地址用来多播,E类地址做保留地址。
另外还有一些特殊地址:
①. 例如主机号全为 1 是该网络的广播地址(例如在一个C类地址的网络中,192. 192 . 192 . 255 , 网络号是前面三个字节, 主机号是后面的一个字节,8位全为1,那么这个地址则是 网络号位 192.192.192.0这个网络的广播地址)。其中 255 . 255 . 255 . 255也是主机所在网络的广播地址;
②. 主机号全为 0 则是该网络的网络地址;
③. 127 . 0 . 0 . 0 ~ 127 . 255 . 255 . 255是主机会送地址,通常用来做网络测试,调试主机与路由是否连接畅通;
④. 其中 10 . 0 . 0 . 0 ~ 10 . 255 . 255 . 255、172 . 16 . 0 . 0 ~ 172 . 31 . 255 . 255、192 . 168 . 0 . 0 ~ 192 . 168 . 255 . 255保留给内部网络使用。

2.4.2 子网掩码、超网

传统的IP地址分类确定是不能在网络内部使用路由,这样对于较大的网络,例如一个A类网络,由于主机数太多而变得难以管理,为此引入了子网掩码以从一个大网络上划分成一些小网络。子网掩码由一系列 0 和 1 构成,通过与IP地址做与运算来得到一个IP地址的网络号,例如A类地址的子网掩码是 255 . 0 . 0 . 0,B类地址的子网掩码是 255 . 255 . 0 . 0,C类地址的子网掩码是 255 . 255 . 255 . 0。要是想将一个B类地址(例:129 . 145 . 0 . 0)划分为多个小的C类网络,只需要将其子网掩码设为 255 . 255 . 255 . 0就可以了,这样 129 . 145 . 1 . 0和 129 . 145 . 2 . 0就属于不同网络了,因为虽然是B类地址,但是与给定的子网掩码做与运算出来的网络号不一样了,就属于不同网络。像这样通过子网掩码将一个大网络划分成若干个小网络叫做划分子网。
超网:与子网功能相反,将若干个小网络划分成一个大网络。例如一个单位分配到了8个C类(前三个字节为网络号)地址:202 . 120 . 224 . 0 ~ 202 . 120 . 231 . 0,只要将其子网掩码设置为 255 . 255 . 248 . 0 就能使这些C类网络相通。(PS:这个结果是怎么得来的我现在还不明白,等日后明白了再补上)

3、TCP协议

3.1 概念

TCP协议是用于主机到主机的通信协议。他是面向连接的端到端的可靠协议,提供可靠字节流传输和对上层应用提供连接服务。TCP协议建立在IP协议的基础之上,可以根据IP协议提供的服务传输大小不定的数据段。IP协议负责数据的分段、重组及在多种网络和互联的网关间传输数据报。
为了在不可靠的IP数据传输服务上实现面向连接的可靠数据传输,TCP协议使用序列号和应答号来保证其传输的可靠性,TCP协议是面向字节流的,每个字节都有一个序列号,一个数据段的第一个字节的序列号将随同数据段被发送,并且作为这个数据段的序列号。数据段同时还带有一个应答序号,表明它期望对方下次发送的字节的顺序号。当TCP协议传输一个数据段的时候,会同时将其放入重传队列,并启动一个定时器。如果这个数据段的应答能在定时器超时前收到,那么就将它从重传队列中移除,否则重发此数据段。应答未能收到,既可能是接收方未收到所发数据段,也可能是应答本身丢失。
TCP协议提供了端口来区分他所处理的不同数据流。由于端口号是由操作系统、TCP协议进程或用户自行确定,所以有可能不唯一。为此将网络地址同端口号组合起来形成套接字保证其在整个互联网络上的唯一性。

3.2 TCP协议数据报的头

3.2.1 TCP协议头部格式
TCP协议数据段的头格式.jpg
  • 源端口:发送数据端套接字的端口号

  • 目的端口:目的套接字端口号

  • 顺序号:该数据报第一个数据字节的序列号,用作标识该报文段序列号

  • 应答号:存放的是发送方期望收到的数据段序号,算作是对收到报文的一个确认。ACK标志为 0 时,应答号部分无效(例如首个连接的[SYN]数据包),ACK标志为1时应答号才有效

  • TCP首部长度:标明TCP协议报头长度,单位是32bit即4个字节,其最小值为5(5 x 4 = 20 byte,这个长度是除去可选项的长度),从上图中看出,其规定头部长为 4 bit,所以最大值为 15, 15 x 4 = 60 byte可以算出可选项长度大为40个字节(60 byte - 20 byte = 40 byte)

  • 保留位:保留字段长度为3位,必须全置为0

  • 标记

标志位简写 全写 含义
NS Nonce 有效排除潜在的ECN滥用
CWR Congestion Window Reduced 拥塞窗口减少标志
ECE ECN-Echo ECN标志
URG Urgent 紧急指针有效性标志
ACK Acknowledgment 确认序号有效性标志,一旦一个连接建立起来,该标志总被置为1
PSH Push Push标志(接收方应尽快将报文段提交至应用层)
RST Reset 重置连接标志
SYN Synchronization 同步序号标志(建立连接时候使用)
FIN Fin 传输数据结束标志(断开连接时使用)
  • 窗口:表示发送方还可以接受数据大小,防止对方发送数据大于自己的缓冲数据区,从应答字段的顺序号开始计。

  • 效验和:效验和覆盖整个TCP报文段,强制字段,由发送端计算存储,接收端进行验证

  • 紧急指针:当Urgent标志置1时,紧急指针才有效

  • 可选项:可选项可以有 0 到多个,可选项字段以第一个字节表明其类型,第二个字节表示该可选项的总长度,后面紧跟可选项的值(长度为可选项的总长度-2)。可选项字段可以从任何字节边界开始,但若最后选项长度不足的话,要填充以补足定义的数据段长度。具体解释请看下面 3.2.2

3.2.2 TCP报头可选项字段

TCP报头可选项字段的数据一般拼接格式(不是全部可选项都是这个格式)
类型kind(1byte) + 长度length(1byte) + 值value(length-2byte)

TCP报头可选项和含义:

kind 字段 长度(单位byte)
0 End of Option List (EOL) 0 (没有长度,只有类型)
1 No-Operation (NOP) 0 (没有长度,只有类型)
2 Maximum segment size (MSS) 1 (用一个字节来表示该可选项的总长)
3 Window scale 1 (用一个字节来表示该可选项的总长)
4 SACK Permitted 1 (用一个字节来表示该可选项的总长)
5 SACK 1 (用一个字节来表示该可选项的总长)
8 Timestamps 1 (用一个字节来表示该可选项的总长)
  • ①. End of Option List (EOL):kind = 0,当可选项总长度不够32位的倍数,用该可选项来填补,实际就是用 0 填补

  • ②. No-Operation (NOP):kind = 1no operation,设计该字段主要是用来明确不同可选项之间的分割点,假设有多个可选项的情况下,一般用该可选项来分割下,因此在一个数据包中出现多个nop 也不奇怪的。注意 No-Operation 可选项没有长度和值,只有一个类型占一个字节,也就是有涉及到该可选项解析只需解析一个字节,后面可能是另一个可选项的类型

  • ③. Maximum segment size (MSS):kind = 2最大报文传输段,每一个TCP报文段中数据字段的最大长度,注意:只是数据部分的字段,不包括TCP的头部。TCP在三次握手中,每一方都会通告其期望收到的MSS(MSS只出现在SYN数据包中)如果一方不接受另一方的MSS值则定位默认值536byte。
    MSS值太小或太大都是不合适,太小,例如MSS值只有1byte,那么为了传输这1byte数据,至少要消耗20字节IP头部+20字节TCP头部=40byte,这还不包括其二层头部所需要的开销,显然这种数据传输效率是很低的。MSS过大,导致数据包可以封装很大,那么在IP传输中分片的可能性就会增大,接收方在处理分片包所消耗的资源和处理时间都会增大,如果分片在传输中还发生了重传,那么其网络开销也会增大。因此合理的MSS是至关重要的。MSS的合理值应为保证数据包不分片的最大值。对于以太网MSS可以达到1460byte (MTU(1500byte) - IP首部(20byte) - TCP首部(20byte) = 1460byte)。

  • ④. Window scale:kind = 3窗口扩大选项,我们知道TCP最大的窗口大小为65535byte,在早期网络这是够用的,但随着各种复杂网络的产生,特别是类似卫星通信这种时延和带宽都比较大的通信产生,需要更大窗口来满足性能和高吞吐率,于是窗口扩大选项便产生了。
    我们假设 主机A — 主机B 是一条高速的WAN链路,A向B发送大量数据,由于有足够带宽,那么A在很短时间内就可以发送完 65535byte 的数据,而由于窗口过小,A只能停止发送,直到B对A发送的数据进行ACK确认。假设通信距离较远,延时也由于距离的原因变大,这么一发一确认可能需要等上很长时间,在这个等待的时间里面 A-B 是没有实际数据发送的,因此大量的时间被浪费在了等待对方回应上。
    这个时候我们可以通过增大窗口的大小来使一次可以传输更多的数据,从而减少等待确认的时间。
    窗口扩大选项占值占一个字节,表示移位值S。新的窗口值等于TCP首部的窗口位数从16增大到(16+S)。这相当于把窗口值向左移动S位后获得实际的窗口大小。移位值准许使用的最大值是14,相当于窗口最大值增大到 2^(16+14) = 1073741824 byte = 1048576 kb = 1024 M = 1GB,方便理解和记忆一般用TCP头中的窗口值 x 2^S来表示实际窗口的大小。窗口扩大选项在TCP建立之初进行协商,如果已经实现了窗口扩大,当不再需要其扩大窗口时,发送S=0选项就可以恢复到窗口大小为16位。

  • ⑤. SACK Permitted: kind = 4选择确认选项可以使用,SACK Permitted 选项在TCP建立连接时由SYN数据包中加上(只有类型和长度,没有值),表示该链接允许接下来SACK的实现。

  • ⑥. SACK: kind = 5选择确认选项(Selective Acknowledgements ),我们假设TCP传输中有这种情况出现,收到的报文无差错,只是未按序列号,中间还缺少一些序列号,那么能否只传输缺少的数据,而不重传已经正确到达的数据?这就是选择确认的技术。
    举例:主机A向主机B传输3个数据包,五个包的序号分别是1 2 3,主机B只收到了序号为 1 和 3 的数据包,而中间的2没有收到,那么如果设置可选项SACK的值,这样就可以让A主机知道只传输丢失的序列号为2的块号。
    原理:拿上面的例子来说,丢了2号块,收到1和3块号的数据包,那么回给主机A的确认包对于设置SACK值来说就要有一个上下的边界(表明从序列号为多少的字节传输到序列号为多少的字节中间这段数据),序列号在TCP报头中占4个字节,表示上下边界就需要消耗8个字节(4byte x 2),由上面讲的可知IP可选项的最大长度为 40 个字节,加上表示SACK字段需要占用1个字节,表示长度也需要占一个字节,因此最多可以指明4个字块的边界信息( (40 - 2) / 8 ≈ 4)。

  • ⑦. Timestamps:kind = 8时间戳选项,时间戳选项占10个字节,其中最主要的字段时间戳字段(4字节)和时间戳回送回答字段(4字节)。
    时间戳选项主要的功能有两个:

    • 用来计算往返时间RTT,发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方在确认该报文段时把当前时间赋值到时间戳回送回答字段。因此,发送方在收到确认报文后,可以准确计算出RTT。
    • PAWS:防止回绕的序号,我们知道序列号只有32位,而每增加2^32 = 4294967295 个序列号后就会重复使用原来用过的序列号。假设我们有一条高速网络,通信的主机双方有足够大的带宽用来快速的传输数据。例如1Gb/s的速率发送报文段,则不到35秒钟数据字节的序列号就会重复。这样对TCP传输带来混乱的情况。而采用时间戳选项,可以很容易的分辨出相同序列号的数据报,哪个是最近发送,哪个是以前发送的。
3.2 .3 TCP协议头部数据

下面是我用抓包工具抓到的一个TCP断开的四次握手,其他的咱不管,先看第一次发送FIN类型数据包的TCP数据的头部

IP数据报.png

最下面的是数据,去掉以前面太网首部 14 个字节和IP报头 20 个字节开始是TCP数据报头部分,下面我们对着上面的格式来解析下

先单独把TCP头部数据粘贴下来

//字节为单位 Hex+ASCII方式显示
00 50 d2 21 de ce 92 2b ba da c8 db 50 11 01 9b 57 64 00 00  

//二进制 bit流显示
00000000 01010000 11010010 00100001 
11011110 11001110 10010010 00101011 
10111010 11011010 11001000 11011011 
01010000 00010001 00000001 10011011 
01010111 01100100 00000000 00000000   
字段 位置 含义
源端口 0 - 15 00000000 01010000 网络字节排序解析,源端口为 80
目的端口 16 - 31 11010010 00100001 目的端口 53793
顺序号 32 - 63 11011110 11001110 10010010 00101011 顺序号为~
应答号 64 - 95 10111010 11011010 11001000 11011011 确认号为~
TCP首部长度 96 - 99 0101 长度为20字节 5 x 4 byte = 29 byte
保留位 100 - 102 000 ~
标记 103 - 111 0 00010001 ACK位为 1 标记应答号有效,FIN位为 1 表示该数据包为结束标识数据包
窗口 112 - 127 00000001 10011011 窗口值为411,标识发送套接字缓存区最大容纳411字节数据
效验和 128 - 143 01010111 01100100 ~
紧急指针 144 - 159 00000000 00000000 紧急指针标记位(URG)为1时这里的数据才有效
可选项 ~ ~ ~

3.3 TCP通信数据交互细节和实践

关于TCP连接的三次握手、中间数据交互以及断开连接的四次握手理论部分请参考我前面的一片文章套接字(Socket)编程(二) 内部通信原理,这里就不做重复的解释了

3.3.1 TCP建立连接的三次握手抓包数据部分

首先来看下抓包过程截图

TCP建立连接的三次握手.png

① 客户端发送[SYN]同步消息

//以太网头部+IP报头+TCP报头+TCP数据(字节为单位位 Hex+ASCII方式显示)
88 25 93 02 b7 8c 78 4f 43 5b 56 75 08 00 45 00
00 40 00 00 40 00 40 06 f6 72 0a 16 46 87 cb d0
27 d8 d2 23 01 bb 2e f0 89 c5 00 00 00 00 b0 02
ff ff b3 39 00 00 02 04 05 b4 01 03 03 05 01 01
08 0a 32 a6 80 43 00 00 00 00 04 02 00 00

//提取TCP报头+TCP数据(去掉以太网头部14byte和IP报头20byte)
d2 23 01 bb 
2e f0 89 c5 
00 00 00 00 
b0 02 ff ff 
b3 39 00 00 
02 04 05 b4 01 03 03 05 01 01 08 0a 32 a6 80 43 00 00 00 00 04 02 00 00

解析:从上面可以解析出源端口号为:0xd23 = 353795;目的端口号:0x01bb = 443;序列号:SEQ = 0x2ef089c5;ACK = 0x00000000;TCP报头长为:0xb = 11(32 bit),11 x 4 byte = 44 byte,即TCP报头长为 44 个字节;窗口大小为 0xffff = 65535 byte;
保留位和标志位:0x002 = 0b000000000010;按位解析标志位为 0b000000010,NS: 0,CWR: 0,ECE: 0,URG: 0,ACK: 0,PSH: 0,RST: 0,SYN: 1,FIN: 0,从解析里面可以看出该报文ACK字段无效,只有SYN字段有效,是第一个请求连接[SYN]同步数据报
可选项部分:可以看出该TCP报头最后的24个字节表示可选项,解析如下

02 04 05 b4            kind = 2, len = 4,MMS Value = 0x05b4 表示MSS = 1460byte
01                     kind = 1  No-Operation
03 03 05               kind = 3,len = 3,value = 0x05  窗口选项偏移5位,即实际窗口大小为 0xffff x 2^5
01                     kind = 1  No-Operation
01                     kind = 1  No-Operation
08 0a 32 a6 80 43 00 00 00 00   kind = 8,len = 10  时间戳选项,Timestamp Value(TSval): 0x32a68043 = 849772611,Timestamp echo reply(TSecr): 0
04 02                  kind = 4,len  =2  SACK Permitted,选择确认选项有效
00 00                  kind = 0  补充够32bit,即4byte的倍数

② 服务器回复[SYN+ACK]消息

//以太网头部+IP报头+TCP报头+TCP数据(字节为单位位 Hex+ASCII方式显示)
78 4f 43 5b 56 75 88 25 93 02 b7 8c 08 00 45 00
00 3c 66 f2 00 00 38 06 d7 84 cb d0 27 d8 0a 16
46 87 01 bb d2 23 f4 36 9f 4a 2e f0 89 c6 a0 12
71 20 a5 e3 00 00 02 04 05 a0 04 02 08 0a d6 c8
42 f0 32 a6 80 43 01 03 03 08

//提取TCP报头+TCP数据(去掉以太网头部14byte和IP报头20byte)
01 bb d2 23 
f4 36 9f 4a 
2e f0 89 c6 
a0 12 71 20 
a5 e3 00 00 
02 04 05 a0 04 02 08 0a d6 c8 42 f0 32 a6 80 43 01 03 03 08

解析:从上面可以解析出源端口号为:0x01bb = 443;目的端口号:0xd23 = 353795;序列号:SEQ = 0xf4369f4a;ACK = 0x2ef089c6(即第一个包的SEQ+1,对第一个同步包的确认);TCP报头长为:0xa = 10(32 bit),10 x 4 byte = 40 byte,即TCP报头长为 40 个字节;窗口大小为 0x7120 =28960 byte;
保留位和标志位:0x012 = 0b000000010010;按位解析标志位为 0b000010010,NS: 0,CWR: 0,ECE: 0,URG: 0,ACK: 1,PSH: 0,RST: 0,SYN: 1,FIN: 0,从解析里面可以看出该报文ACK字段和SYN字段有效,是对第一个连接请求包的确认[SYN+ACK]数据报
可选项部分:可以看出该TCP报头最后的20个字节表示可选项,解析如下

02 04 05 a0       kind = 2, len = 4,value = 0x05a0 表示MSS = 1440 byte
04 02             kind = 4  SACK Permitted,选择确认选项有效
08 0a d6 c8 42 f0 32 a6 80 43  kind = 8, len = 10 时间戳选项,Timestamp Value(TSval): 0xd6c842f0 = 36033448560,Timestamp echo reply(TSecr): 0x32a68043 = 849772611
01   kind = 1     NOP
03 03 08  kind = 3, len = 3,value = 8 窗口选项偏移8位,即实际窗口大小为 0x7120 x 2^8

③ 客户端回复[ACK]消息,表示连接成功

//以太网头部+IP报头+TCP报头+TCP数据(字节为单位位 Hex+ASCII方式显示)
88 25 93 02 b7 8c 78 4f 43 5b 56 75 08 00 45 00
00 34 00 00 40 00 40 06 f6 7e 0a 16 46 87 cb d0
27 d8 d2 23 01 bb 2e f0 89 c6 f4 36 9f 4b 80 10
10 09 35 75 00 00 01 01 08 0a 32 a6 80 82 d6 c8
42 f0

//提取TCP报头+TCP数据(去掉以太网头部14byte和IP报头20byte)
d2 23 01 bb 
2e f0 89 c6 
f4 36 9f 4b 
80 10 10 09 
35 75 00 00 
01 01 08 0a 32 a6 80 82 d6 c8 42 f0

解析:从上面可以解析出源端口号为:0xd23 = 353795;目的端口号:0x01bb = 443;序列号:SEQ = 0x2ef089c6;ACK = 0xf4369f4b (即上一个包的SEQ +1,对上一个同步包的确认);TCP报头长为:0x8 = 8(32 bit),8 x 4 byte = 32 byte,即TCP报头长为 32 个字节;窗口大小为 0x1009 =4105 byte;
保留位和标志位:0x010 = 0b000000010000;按位解析标志位为 0b000010000,NS: 0,CWR: 0,ECE: 0,URG: 0,ACK: 1,PSH: 0,RST: 0,SYN: 0,FIN: 0,从解析里面可以看出该报文ACK字段有效,是对上一个服务器确认请求连接包的确认[ACK]数据报
可选项部分:可以看出该TCP报头最后的12个字节表示可选项,解析如下

01     kind = 1     NOP
01     kind = 1     NOP
08 0a 32 a6 80 82 d6 c8 42 f0  时间戳选项,Timestamp Value(TSval): 0x32a68082 = 849772674,Timestamp echo reply(TSecr): 0xd6c842f0 = 36033448560
3.3.2 TCP数据交互抓包数据部分

下面来一组TCP连接中间交换数据部分

① 客户端发送数据

//以太网头部+IP报头+TCP报头+TCP数据(字节为单位位 Hex+ASCII方式显示)
88 25 93 02 b7 8c 78 4f 43 5b 56 75 08 00 45 00
00 f5 00 00 40 00 40 06 f5 bd 0a 16 46 87 cb d0
27 d8 d2 23 01 bb 2e f0 89 c6 f4 36 9f 4b 80 18
10 09 43 d2 00 00 01 01 08 0a 32 a6 80 82 d6 c8
42 f0  + 193byte TCP数据

//提取TCP报头+TCP数据(去掉以太网头部14byte和IP报头20byte)
d2 23 01 bb 
2e f0 89 c6 
f4 36 9f 4b 
80 18 10 09 
43 d2 00 00 
01 01 08 0a 32 a6 80 82 d6 c8 42 f0  
+ 193byte TCP数据

解析:从上面可以解析出源端口号为:0xd23 = 353795;目的端口号:0x01bb = 443;序列号:SEQ = 0x2ef089c6;ACK = 0xf4369f4b;TCP报头长为:0x8 = 8(32 bit),8 x 4 byte = 32 byte,即TCP报头长为 32 个字节;窗口大小为 0x1009 =4105 byte;
保留位和标志位:0x018 = 0b000000011000;按位解析标志位为 0b000011000,NS: 0,CWR: 0,ECE: 0,URG: 0,ACK: 1,PSH: 1,RST: 0,SYN: 0,FIN: 0,从解析里面可以看出该报文ACK字段和PUSH有效,希望传输层尽快将数据交到应用层
可选项部分:可以看出该TCP报头最后的12个字节表示可选项

② 服务器端回复ACK确认

//以太网头部+IP报头+TCP报头+TCP数据(字节为单位位 Hex+ASCII方式显示)
78 4f 43 5b 56 75 88 25 93 02 b7 8c 08 00 45 00
00 34 66 fa 00 00 38 06 d7 84 cb d0 27 d8 0a 16
46 87 01 bb d2 23 f4 36 9f 4b 2e f0 8a 87 80 10
00 76 44 09 00 00 01 01 08 0a d6 c8 43 2e 32 a6
80 82

//提取TCP报头+TCP数据(去掉以太网头部14byte和IP报头20byte)
01 bb d2 23 
f4 36 9f 4b 
2e f0 8a 87 
80 10 00 76 
44 09 00 00 
01 01 08 0a d6 c8 43 2e 32 a6 80 82

解析:从上面可以解析出源端口号为:0x01bb = 443;目的端口号:0xd23 = 353795;序列号:SEQ = 0xf4369f4b;
ACK = 0x2ef08a87(前面数据包的SEQ(0x2ef089c6) + 193 = 0x2ef08a87 PS:这里需要注意下,很多网络和书上都说这个ACK的值应该是上个包的SEQ + TCP数据大小 + 1,这种说法是不准确的,拿上个数据来讲,数据的第一个字节序号也就是上个数据包的序号是0x2ef089c6,那么第二个字节序号就是0x2ef089c7,现在TCP数据一共是193个字节,那么接下来的第194个字节序号应该是0x2ef089c6 + 193 = 0x2ef08a87,所以服务器期望收到下个包的序号应该是0x2ef08a87)
TCP报头长为:0x8 = 8(32 bit),8 x 4 byte = 32 byte,即TCP报头长为 32 个字节;窗口大小为 0x0076 = 118 byte;
保留位和标志位:0x010 = 0b000000010000;按位解析标志位为 0b000010000,NS: 0,CWR: 0,ECE: 0,URG: 0,ACK: 1,PSH: 0,RST: 0,SYN: 0,FIN: 0,从解析里面可以看出该报文ACK字段有效,对上个数据包的一个确认,表示可以接着传送后面的数据了(从字节编号为0x2ef08a87开始),是一个[ACK]确认数据报
可选项部分:可以看出该TCP报头最后的12个字节表示可选项

3.3.3 TCP断开连接的四次握手抓包数据部分

首先来看下抓包过程截图

TCP断开四次握手.png

① 主动断开方发送[FIN]数据报

//以太网头部+IP报头+TCP报头+TCP数据(字节为单位位 Hex+ASCII方式显示)
78 4f 43 5b 56 75 88 25 93 02 b7 8c 08 00 45 00
00 34 89 5e 40 00 39 06 a4 3f 7a e4 48 a5 0a 16
46 87 00 50 d2 1e a9 ba 9e eb 65 ee 19 b0 80 11
03 cc 9e 50 00 00 01 01 08 0a 41 fa 79 05 32 a6
38 20

//提取TCP报头+TCP数据(去掉以太网头部14byte和IP报头20byte)
00 50 d2 1e 
a9 ba 9e eb 
65 ee 19 b0 
80 11 03 cc 
9e 50 00 00 
01 01 08 0a 41 fa 79 05 32 a6 38 20

解析:从上面可以解析出源端口号为:0x0050 =80;目的端口号:0xd21e =53790;序列号:SEQ = 0xa9ba9eeb;ACK = 0x65ee19b0;TCP报头长为:0x8 = 8(32 bit),8 x 4 byte = 32 byte,即TCP报头长为 32 个字节;窗口大小为 0x03cc =972 byte;
保留位和标志位:0x011 = 0b000000010001;按位解析标志位为 0b000010001,NS: 0,CWR: 0,ECE: 0,URG: 0,ACK: 1,PSH: 0,RST: 0,SYN: 0,FIN: 1,从解析里面可以看出该报文ACK字段和FIN字段有效,是请求断开连接的[FIN+ACK]数据报
可选项部分:可以看出该TCP报头最后的12个字节表示可选项,解析如下

01     kind = 1     NOP
01     kind = 1     NOP
08 0a 41 fa 79 05 32 a6 38 20 时间戳选项,Timestamp Value(TSval): 1106934021,Timestamp echo reply(TSecr): 849754144

② 被断开方发送[ACK]数据包,对主动对方数据报进行确认

//以太网头部+IP报头+TCP报头+TCP数据(字节为单位位 Hex+ASCII方式显示)
88 25 93 02 b7 8c 78 4f 43 5b 56 75 08 00 45 00
00 34 00 00 40 00 40 06 26 9e 0a 16 46 87 7a e4
48 a5 d2 1e 00 50 65 ee 19 b0 a9 ba 9e ec 80 10
10 00 1d d9 00 00 01 01 08 0a 32 a6 ac 63 41 fa
79 05

//提取TCP报头+TCP数据(去掉以太网头部14byte和IP报头20byte)
d2 1e 00 50 
65 ee 19 b0 
a9 ba 9e ec 
80 10 10 00 
1d d9 00 00 
01 01 08 0a 32 a6 ac 63 41 fa 79 05

解析:从上面可以解析出源端口号为:0xd21e =53790;目的端口号:0x0050 =80;序列号:SEQ = 0x65ee19b0;ACK = 0xa9ba9eec ;TCP报头长为:0x8 = 8(32 bit),8 x 4 byte = 32 byte,即TCP报头长为 32 个字节;窗口大小为 0x1000 = 4096 byte;
保留位和标志位:0x010 = 0b000000010000;按位解析标志位为 0b000010000,NS: 0,CWR: 0,ECE: 0,URG: 0,ACK: 1,PSH: 0,RST: 0,SYN: 0,FIN: 0,从解析里面可以看出该报文ACK字段有效,是对断开连接请求的确认[ACK]数据报
可选项部分:可以看出该TCP报头最后的12个字节表示可选项,解析如下

01     kind = 1     NOP
01     kind = 1     NOP
08 0a 32 a6 ac 63 41 fa 79 05 时间戳选项,Timestamp Value(TSval): 849783907 ,Timestamp echo reply(TSecr): 1106934021

③ 被断开方处理完自己的逻辑,发送[FIN]数据报到断开方

//以太网头部+IP报头+TCP报头+TCP数据(字节为单位位 Hex+ASCII方式显示)
88 25 93 02 b7 8c 78 4f 43 5b 56 75 08 00 45 00
00 34 00 00 40 00 40 06 26 9e 0a 16 46 87 7a e4
48 a5 d2 1e 00 50 65 ee 19 b0 a9 ba 9e ec 80 11
10 00 1d d8 00 00 01 01 08 0a 32 a6 ac 63 41 fa
79 05

//提取TCP报头+TCP数据(去掉以太网头部14byte和IP报头20byte)
d2 1e 00 50
65 ee 19 b0 
a9 ba 9e ec 
80 11 10 00 
1d d8 00 00 
01 01 08 0a 32 a6 ac 63 41 fa 79 05

解析:从上面可以解析出源端口号为:0xd21e =53790;目的端口号:0x0050 =80;序列号:SEQ = 0x65ee19b0 ;ACK = 0xa9ba9eec ;TCP报头长为:0x8 = 8(32 bit),8 x 4 byte = 32 byte,即TCP报头长为 32 个字节;窗口大小为 0x1000 = 4096 byte;
保留位和标志位:0x011 = 0b000000010001;按位解析标志位为 0b000010000,NS: 0,CWR: 0,ECE: 0,URG: 0,ACK: 1,PSH: 0,RST: 0,SYN: 0,FIN: 1,从解析里面可以看出该报文ACK字段和FIN字段有效,是被断开方发送的断开连接[FIN+ACK]数据报
可选项部分:可以看出该TCP报头最后的12个字节表示可选项,解析如下

01     kind = 1     NOP
01     kind = 1     NOP
08 0a 32 a6 ac 63 41 fa 79 05 时间戳选项,Timestamp Value(TSval): 849783907 ,Timestamp echo reply(TSecr): 1106934021

④ 断开方对被对开放发送的断开数据报发送[ACK]数据报进行确认

//以太网头部+IP报头+TCP报头+TCP数据(字节为单位位 Hex+ASCII方式显示)
78 4f 43 5b 56 75 88 25 93 02 b7 8c 08 00 45 00
00 34 42 6b 40 00 39 06 eb 32 7a e4 48 a5 0a 16
46 87 00 50 d2 1e a9 ba 9e ec 65 ee 19 b1 80 10
03 cc 29 f7 00 00 01 01 08 0a 41 fa 79 1a 32 a6
ac 63

//提取TCP报头+TCP数据(去掉以太网头部14byte和IP报头20byte)
00 50 d2 1e 
a9 ba 9e ec 
65 ee 19 b1 
80 10 03 cc 
29 f7 00 00 
01 01 08 0a 41 fa 79 1a 32 a6 ac 63

解析:从上面可以解析出源端口号为:0x0050 =80;目的端口号:0xd21e =53790;序列号:SEQ = 0xa9ba9eec;ACK = 0x65ee19b1;TCP报头长为:0x8 = 8(32 bit),8 x 4 byte = 32 byte,即TCP报头长为 32 个字节;窗口大小为 0x03cc =972 byte;
保留位和标志位:0x010 = 0b000000010000;按位解析标志位为 0b000010000,NS: 0,CWR: 0,ECE: 0,URG: 0,ACK: 1,PSH: 0,RST: 0,SYN: 0,FIN: 0,从解析里面可以看出该报文ACK字段有效,是对断开连接请求的确认[ACK]数据报
可选项部分:可以看出该TCP报头最后的12个字节表示可选项,解析如下

01     kind = 1     NOP
01     kind = 1     NOP
08 0a 41 fa 79 1a 32 a6 ac 63 时间戳选项,Timestamp Value(TSval): 1106934042,Timestamp echo reply(TSecr): 849783907

4、UDP协议

UDP协议是IP协议上层的另一个重要协议,他是面向无连接的、不可靠的数据报传输协议,他仅仅将要发送的数据报传送至网络,并接受从网络上传来的数据报,而不与远端的UDP协议模块建立连接。UDP协议为用户的网络应用程序提供服务。

4.1 UDP协议数据报头

4.1.1 UDP协议头部格式
UDP报头.jpg
  • 源端口:套接字发送端端口号
  • 目的端口:目的套接字端口号
  • 数据包长:UDP报头+UDP数据报的长度,单位1byte
4.1.2 UDP协议头部数据
//以太网头部+IP报头+UDP报头+UDP数据(字节为单位位 Hex+ASCII方式显示)
01 00 5e 4b 00 fe f8 32 e4 8a ef e5 08 00 45 00
00 74 49 b6 00 00 01 11 2f 50 0a 16 46 14 ef 4b
00 fe c1 5f 26 e5 00 60 19 b1 00 00 00 58 4f 47
45 4d 52 41 59 2d 4e 42 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 4a
52 40 31 32 33 34 35 36 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00

//UDP报头+UDP数据(去掉以太网头部14byte和IP报头20byte)
c1 5f 26 e5 00 60 19 b1 
00 00 00 58 4f 47 45 4d 52 41 59 2d 4e 42 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 41 4a 52 40 31 32 33 34 35 36 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00

从上面数据抓包可以看出:
源端口:0xc15f = 49503
目的端口:0x26e5 = 9957
数据包长(UDP报头加+UDP数据):0x0060 = 96 byte
效验值:0x18b1

5、结语

对于TCP/IP通信的基本原理和过程就总结到这,顺带说下上面的抓包软件叫Wireshark

Socket编程
Web note ad 1