探究背景: 我们经常说 TCP 是传输层协议, IP 是网络层协议, HTTP 协议是应用层协议等等, 那么究竟他们三者是如何融洽的工作在一起的呢? 我们今天主要来实验探究一下 TCP 和 HTTP 到底是怎么结合的.
实验环境:
server:192.168.254.136, 使用 httpd 作为 web 服务, 复制 nginx 的首页静态页作为 demo
client:192.168.254.1,wireshark 抓包
实验步骤:
从客户端访问服务器端, 抓取数据包.
报文摘录:
报文分析:
1, 第一步, 老生成谈的 TCP 三次握手机制, 先进行了三次握手, 然后建立连接, 此处不再展开.
2, 接下来, 4 号数据包是客户端向服务器端发送 HTTP 的 get 请求, 内容略.
3, 然后是这次我要说的重点部分了. 4 号报文是客户端向服务器端发送了请求, 那么 5 号报文则开始响应这次请求, 第一个 TCP 包并没有包含任何有效载荷, 只有一个 60 字节的 TCP 头. 我们展开这个报文看看 60 字节包含什么.
目的 mac:6B
源 mac: 6B
ipv4 类型: 2B
------------------------------------------------------------------------------------------------------------------------------
IP 版本: 0.5B
头部长度: 0.5B
服务类型: 1B
总长度: 2B
标识: 2B
标志: 3bits 片偏移: 13bits 共 2B
TTL: 1B
协议: 1B
校验和: 2B
源 IP: 4B
目的 IP: 4B
-------------------------------------------------------------------------------------------------------------------------------
源端口: 2B
目的端口: 2B
序列号: 4B
确认号: 4B
头部长度: 0.5B
保留字段: 6bits
URG/ACK/PSH/RST/SYN/FIN 各 1bit
窗口大小: 2B
校验和: 2B
紧急指针: 2B
--------------------------------------------------------------------------------------------------------------------------------
padding:6B 填充字段, 放置在数据链路层中.
IP 报文分析:
4 位版本号: IP 协议 (IPv4) 版本号位 4
4 位头部长度: 标识头部有多少个 4 字节, 即最大共 15*4 个字节
8 位服务类型: 包含一个 4 位优先权字段: 最小延时, 最大吞吐量, 最高可靠性和最小费用.
16 位总长度: 表示整个 IP 数据报的长度, 最大表示 65535, 但由于 MTU 限制, 一般无法到达这个值.
16 位标识: 唯一的标识数据报. 系统采用加 1 的方式边发送边赋值.
3 位标识(保留, DF 禁止分片, MF 更多分片): 所以这个标志是为分片存在, DF 设置时禁止分片所以如果数据报太大则发送失败. MF 设置时, 如果产生分片, 除了最后一个分片, 其他此片置 1.
13 位分片偏移: 分片相对原始 IP 数据报开始处的偏移.
8 位生存时间(TTL): 数据报到达目的地之前允许经过的路由跳跳数. 跳一下减 1, 得 0 丢弃.
8 位协议: 用来区分上层协议(ICMP 为 1,TCP 为 6,UDP 为 17).
16 位头部校验和: 仅以 CRC 算法检验数据报头部在传输过程中是否损坏.
32 位源 IP 和目的 IP.
TCP 报文分析:
16 位源端口号和 16 位目的端口号.
32 位序号: 一次 TCP 通信过程中某一个传输方向上的字节流的每个字节的编号, 通过这个来确认发送的数据有序, 比如现在序列号为 1000, 发送了 1000, 下一个序列号就是 2000.
32 位确认号: 用来响应 TCP 报文段, 给收到的 TCP 报文段的序号加 1, 三握时还要携带自己的序号.
4 位头部长度: 标识该 TCP 头部有多少个 4 字节, 共表示最长 15*4=60 字节. 同 IP 头部.
6 位保留. 6 位标志. URG(紧急指针是否有效)ACK(表示确认号是否有效)PSH(提示接收端应用程序应该立即从 TCP 接收缓冲区读走数据)RST(表示要求对方重新建立连接)SYN(表示请求建立一个连接)FIN(表示通知对方本端要关闭连接)
16 位窗口大小: TCP 流量控制的一个手段, 用来告诉对端 TCP 缓冲区还能容纳多少字节.
16 位校验和: 由发送端填充, 接收端对报文段执行 CRC 算法以检验 TCP 报文段在传输中是否损坏.
16 位紧急指针: 一个正的偏移量, 它和序号段的值相加表示最后一个紧急数据的下一字节的序号.
分析完这 60 个字节的 TCP 报文之后再接着看 6 号报文, 这个同样是服务器端发送给客户端的 TCP 报文, 与上一个报文看看有何不同. 我们来逐个对比一下上述字段.
首先就是整个 IP 数据报的长度不一样了, 一个是 40 一个是 1500, 然后标识不一样了, 由 17800 变成了 17801, 验证了刚刚说的自增的方式排序. 当然校验和肯定也就不一样了, 所以 IP 数据报文只有这两处不同, 不算校验和.
TCP 报文中前面部分除了校验和均相同, 只是在最后附加了一个 1460 字节的数据字段, 那么多个数据包之间有什么联系呢?
我们单独看 5-8 这几个包, 当客户端发出请求后, 服务器端先发送一个空的 TCP 包, 所以 Seq=1,Len=0, 下一个包的 Seq 仍然是 1, 但是长度变成了 1460, 那么第三个 TCP 包的 Seq 则为 1+1460, 即 Seq2=Seq1+Len. 而 ACK 不变, 那么客户端接受之后发送反馈包, Seq 为服务器端的 Ack 数字, Ack 为上一个数据包的 Seq+Len, 即 1461+1460=2921.
然后服务器端继续向客户端发送数据, 9 号报文的序列号为 2921, 是客户端响应报文中的 Ack,Ack 仍然是 370, 长度为 1460.10 号报文的 Seq 也是 9 号报文的 Seq+Len=2921+1460=4381,11 号为客户端响应报文, Seq 保持 370 不变, Ack 为 4381+1460=5841.
同样的道理, 下面三个数据包也符合这个规律. 最后传输完毕, 第 15 个报文组成一段完整的 HTTP 报文.
但是需要注意的是, 尽管第 15 个包在 wireshark 里是写的 HTTP, 但实际上这个包也是 TCP 的数据包, 包含 TCP 的数据!
我们来看, 前四行都是和普通的 TCP 报文是一样的, 并且长度为 1431, 不足 1460, 说明传输完成了.
最后两行是 HTTP 报文, 也就是说收到了全部的 TCP 传输报文, 并合并为一个完整的 HTTP 应答报文.
然后 TCP 四次断开, 不再详解. 提示一点就是, 16 号包 Seq 是 15 号包中的 Seq+Len 即: 10192=8761+1431,17 号包的 Ack 是 16 号包的 Seq+1
来源: http://blog.51cto.com/hebutyx/2155406