1.4.1 网络协议
网络上传递的二进制数据是分层的。经典的模型有TCP/IP的四层网络协议、OSI的七层网络协议[16]。
网络协议分层的结果,是在应用层数据包前面,附加若干协议头,如图1-16所示,括号内数字为该部分通常所占的字节数。
图1-16 网络协议分层
MAC地址与MAC头
互联网由主机(Host)、路由器(Router)和网关(Gateway)等设备连接而成。
计算机和手机终端通过自带的网卡连接到某个路由器,从而获得与互联网的物理连接。
有线网卡使用有线连接路由器,最常见的物理层协议为802.3以太网协议。
无线网卡使用无线电信号(Wi-Fi),最常见的物理层协议为802.11协议族。
为了区分每个物理层的网卡设备,在链路层,为每个网卡都定义了一个MAC(Media Access Control)地址,又叫网卡的物理地址。
MAC地址是一个6字节的数值,前3字节定义了厂商,后3字节由厂商定义设备。
一个典型的MAC地址为00-01-6C-06-A6-29。
任意网络包的最前面通常都包含一个MAC头,这是一个14字节的数据。
MAC头定义了一对物理连接主机,同时定义了上层协议的类型,如表1-6所示。
表1-6 MAC头的格式
IP地址与IP头
MAC头标识了相邻主机之间的传输,我们需要解决的是互联网上任意两台主机之间的传输。如何定义互联网上任意的机器地址呢?这就是IP(Internet Protocol)层要解决的问题。我们为每个网络中的主机都分配一个IP地址。
早期的IP地址是4字节的,通常称为IPv4。一个典型的IPv4地址为:10.83.241.172,每个部分为0~255的数字。
根据适用网络的大小,IP地址可分为A~E共5类,比如C类地址可有254台主机。
IP头通常是一个20字节的数据块,IP头的格式如表1-7所示。
表1-7 IP头的格式
在局域网中,已知对方的IP地址,想知道其MAC地址,需要查询本机上的ARP(Ad dress Resolution Protocol)表。
在Windows上使用命令arp-a;在macOS/UNIX上使用命令arp-n。
若ARP表为空,则该工具会发送ARP广播收集各个主机的MAC地址。
如果已知MAC地址,想要反查其IP地址,也可以通过此表实现。
若要查看本机的IP地址,在Windows上使用ipconfig命令,在macOS/UNIX上使用ifconfig命令。这个命令在macOS下也可以看到MTU(Maxinum Trasnsmission Unit)值,当MTU值为1500的时候,IP层是不需要分段(Fragment)的。
IP层有两个有用的工具,都基于ICMP(Internet Control Message Protocol)包实现。
·想要看到一个IP网络是否通畅,可以使用ping命令。
·想要看到一个IP路径上会经过哪几个路由器,可以使用tracert命令。它实际上是从步长1开始,连续发TTL=1,2,3,…的ICMP包,让沿路节点返回TTL过期的回应,从而得到对应的IP地址。
随着IPv4地址的枯竭,IPv6技术应运而生。每个IPv6地址都使用128位16字节表示。一个典型的IPv6地址为ff1:ce00:1285:869:2052:be84:e6e0。
UDP和TCP
IP层解决了任意两台主机之间的连通性问题,然而两台主机之间应该会有很多要通信的内容类型,有的涉及网络诊断,有的涉及应用数据。在传输层,我们通过定义2字节的端口(Port)来区分服务,端口号的范围是0~65535。
最简单的传输层是UDP(User Datagram Protocol),它只有8字节,如表1-8所示。
表1-8 UDP头的格式
UDP只保证包能发出,并不确保对方一定能收到。发出去的UDP包,只会层层路由到目的地址,不会有任何回应。
为了保证应用层的可靠传输,人们设计了TCP(Transmission Control Protocol)。TCP的协议头至少有20字节,如表1-9所示。
表1-9 TCP头的格式
为了确保对方一定能收到包,TCP做了以下3件事。
(1)每个发出去的包都有一个编号SEQ,对方收到后会回应ACK=SEQ+1的回包。
(2)如果长时间(具体见下文)没有收到回应包,则TCP会选择超时重发。
(3)如果超时重发还是没收到回应包,则TCP会将等待时长翻倍,并再次重发。
TCP将一个包从发出到收到回应的时间,定义为往返时间(Round Trip Time,RTT)。
每个TCP连接都会动态维护一个RTT数值。每新收到一个回包,就用式(1.1)更新。
其中,0≤α<1,且α越小,对延迟变化越灵敏,通常取α=0.125。
对于超时重发时间(Retransmission Time Out,RTO),有RTO=β×RTT,通常取β=2。
例如,如果RTT=0.5s,则超时重发时间点通常为2×RTT=1s,之后每次翻倍,为2s,4s,8s,…这里采用指数级退避算法,是为了保证网络不被拥堵。
TCP使用三次握手,提前为通信双方保留必要的资源。包类型为SYN包、SYN+ACK包和ACK包。在断开连接时,双方分别发送FIN包,响应FIN+ACK包,共四次挥手。
TCP使用了滑动窗口,来对每个发出去待确认的包进行加窗式队列管理,这增大了同时等待回包的并发数。
为了提高数据包的负载效率,TCP会使用Nagle算法,等若干包积累一段时间后再一起发送,可以使用TCP_NODELAY选项关闭该特性。
加密与解密
网络中未加密的数据都是明文传输的,想要保密就必须加密。常见的加密算法分为两类:对称加密和非对称加密,如图1-17所示。
图1-17 加密与解密
所谓对称加密,就是加密用的密钥(Key)和解密用的密钥是同一个。密钥通常是一个很短的字节码,比如16字节或32字节,它是加密算法得到不同加密结果的关键。
非对称加密则使用不同的公钥和私钥。公钥是公开的,人人都可以获取使用;私钥只有自己知道。
由于非对称加密比较慢,在SSL或TLS之类的加密方法中,通常使用非对称加密来传递对称加密的密钥,再进行对称加密传输。
常见的非对称加密算法有RSA、DSA、ECDSA等。
常见的对称加密算法有DES、3DES、AES等。
另外有一类消息摘要算法,它们将输入的任意长度字节转换为固定长度字节。如MD5固定输出16字节,SHA-1固定输出20字节。这种转换是不可逆的,我们常用这类算法来提取一段字节的特征,用作密钥生成、内容校验等。
接下来,我们将介绍如何进行UDP和TCP编程。