最底下是实际的二进制数据,中间是解析出来的各个字段值,可以看到其中最底部为 HTTP 协议(Hypertext Transfer Protocol),在 HTTP 之前有 54 字节(0×36),这就是底层网络协议所带来的开销,我们接下来对这些协议进行分析。
在 HTTP 之上是 TCP 协议(Transmission Control Protocol),它的具体内容如下图所示:
通过底部的二进制数据,可以看到 TCP 协议是加在 HTTP 文本前面的,它有 20 个字节,其中定义了本地端口(Source port)和目标端口(Destination port)、顺序序号(Sequence Number)、窗口长度等信息,以下是 TCP 协议各个部分数据的完整介绍:
0 1 2 301234567890123456789012345678901
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data| |U|A|E|R|S|F| |
|Offset|Reserved |R|C|O|S|Y|I| Window |
| | |G|K|L|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
具体各个字段的作用这里就不介绍了,感兴趣的读者可以阅读 RFC 793,并结合抓包分析来理解。
需要注意的是,在 TCP 协议中并没有 IP 地址信息,因为这是在上一层的 IP 协议中定义的,如下图所示:
IP 协议同样是在 TCP 前面的,它也有 20 字节,在这里指明了版本号(Version)为 4,源(Source) IP 为 192.168.1.106,目标(Destination) IP 为 119.75.217.56,因此 IP 协议最重要的作用就是确定 IP 地址。
因为 IP 协议中可以查看到目标 IP 地址,所以如果发现某些特定的 IP 地址,某些路由器就会。。。
但是,光靠 IP 地址是无法进行通信的,因为 IP 地址并不和某台设备绑定,比如你的笔记本的 IP 在家中是 192.168.1.1,但到公司就变成172.22.22.22 了,所以在底层通信时需要使用一个固定的地址,这就是 MAC(media access control) 地址,每个网卡出厂时的 MAC 地址都是固定且唯一的。
因此再往上就是 MAC 协议,它有 14 字节,如下所示:
当一台电脑加入网络时,需要通过 ARP 协议告诉其它网络设备它的 IP 及对应的 MAC 地址是什么,这样其它设备就能通过 IP 地址来查找对应的设备了。
最顶上的 Frame 是代表 Wireshark 的抓包序号,并不是网络协议。
就这样,我们解答了第二个问题,不过其实这里面还有很多很多细节没介绍。
第三个问题:数据如何从本机网卡发送到服务器?
从内核到网络适配器(Network Interface Card)
前面说到调用 Socket API 后内核会对数据进行底层协议栈的封装,接下来启动 DMA 控制器,它将从内存中读取数据写入网卡。
以 Nexus 5 为例,它使用的是博通 BCM4339 芯片通信,接口采用了 SD 卡一样的 SDIO,但这个芯片的细节并没有公开资料,所以这里就不讨论了。
连接 Wi-Fi 路由
Wi-Fi 网卡需要通过 Wi-Fi 路由来与外部通信,原理是基于无线电,通过电流变化来产生无线电,这个过程也叫「调制」,而反过来无线电可以引起电磁场变化,从而产生电流变化,利用这个原理就能将无线电中的信息解读出来就叫「解调」,其中单位时间内变化的次数就称为频率,目前在 Wi-Fi 中所采用的频率分为 2.4 GHz 和 5 GHz 两种。
在同一个 Wi-Fi 路由下,因为采用的频率相同,同时使用时会发生冲突,为了解决这个问题,Wi-Fi 采用了被称为 CSMA/CA 的方法,简单来说就是在传输前先确认信道是否已被使用,没有才发送数据。
而同样基于无线电原理的 2G/3G/LTE 也会遇到类似的问题,但它并没有采用 Wi-Fi 那样的独占方案,而是通过频分(FDMA)、时分(TDMA)和码分(CDMA)来进行复用,具体细节这里就不展开了。以小米路由为例,它使用的芯片是 BCM 4709,这个芯片由 ARM Cortex-A9 处理器及流量(Flow)硬件加速组成,使用硬件芯片可以避免经过操作系统中断、上下文切换等操作,从而提升了性能。
路由器中的操作系统可以基于 OpenWrt 或 DD-WRT 来开发的,具体细节我不太了解,所以就不展开了。
因为内网设备的 IP 都是类似 192.168.1.x 这样的内网地址,外网无法直接向这个地址发送数据,所以网络数据在经过路由时,路由会修改相关地址和端口,这个操作称为 NAT 映射。
最后家庭路由一般会通过双绞线连接到运营商网络的。
运营商网络内的路由
数据过双绞线发送到运营商网络后,还会经过很多个中间路由转发,读者可以通过 traceroute 命令或者在线可视化工具来查看这些路由的 ip 和位置。
当数据传递到这些路由器后,路由器会取出包中目的地址的前缀,通过内部的转发表查找对应的输出链路,而这个转发表是如何得到的呢?这就是路由器中最重要的选路算法了,可选的有很多,我对这方面并不太了解,看起来维基百科上的词条列得很全。
主干网间的传输
对于长线的数据传输,通常使用光纤作为介质,光纤是基于光的全反射来实现的,使用光纤需要专门的发射器通过电致发光(比如 LED)将电信号转成光,比起前面介绍的无线电和双绞线,光纤信号的抗干扰性要强得多,而且能耗也小很多。
既然是基于光来传输数据,数据传输速度也就取决于光的速度,在真空中的光速接近于 30 万千米/秒,由于光纤包层(cladding)中的折射率(refractive index)为 1.52,所以实际光速是 20 万千米/秒左右,从首都机场飞往广州白云机场的距离是 1967 千米,按照这个距离来算需要花费 10 毫秒才能抵达。这意味着如果你在北京,服务器在广州,等你发出数据到服务器返回数据至少得等 20 毫秒,实际情况预计是 2- 3 倍,因为这其中还有各个节点路由处理的耗时,比如我测试了一个广州的 IP 发现平均延迟为 60 毫秒。
这个延迟是现有科技无法解决的(除非找到超过光速的方法),只能通过 CDN 来让传输距离变短,或尽量减少串行的来回请求(比如 TCP 建立连接所需的 3 次握手)。
robots.txt 的作用及写法