1 应用层
1.1 体系结构
1.1.1 客户-服务端体系结构
客户端和服务端通过网络连接进行通信,客户端向服务端发送请求,服务端对请求进行处理,并返回响应;请求和响应数据流向一般都是单向的,服务端在处理请求时,可以访问本地的数据和资源,能够提供更加复杂的服务和功能。
1.1.2 P2P 体系结构
节点之间没有明显的客户端和服务端之分,每个节点在网络中都具有相同的地位,可以进行请求和响应。数据流动方式一般是双向的,所有节点都可以提供和接收数据、服务和资源。
1.2 HTTP
HTTP 即超文本传输协议,定义了 Web 客户向 Web 服务器请求 Web 页面的方式,以及服务器向客户传送 Web 页面的方式。
1.2.1 持续连接与非持续连接
HTTP 0.9 采用非持续连接:
- TCP连接开启;
- 最多一个对象通过该TCP连接发送;
- 该TCP连接关闭。
HTTP 1.1 采用持续连接:
- TCP连接开启;
- 多个对象通过该TCP连接发送;
- 该TCP连接关闭。
1.2.2 HTTP 报文格式
请求报文
-
请求行:包含请求方法、URL 和 HTTP 协议版本;
-
首部行:包含请求信息,比如客户端类型、能接收的文档类型、浏览器支持的压缩类型等;
-
空行:HTTP协议规定请求头部必须以一个空行结束;
-
实体体:POST请求才有。
响应报文
-
状态行:包含 HTTP版本、状态码和状态信息,状态码用来表示服务器的响应状态;
-
首部行:包含响应信息,比如数据类型、响应长度、服务器类型等;
-
空行:HTTP 协议规定响应头部必须以一个空行结束;
-
实体体:服务器返回的具体数据,例如 HTML 页面、图片、JSON 数据等。
1.3 Cookie
Cookie 既存在于本地客户端,又存在于云端服务器,能够实现跟踪记录的功能,共有 4 个组件:
-
HTTP 响应报文的 cookie 首部行;
-
HTTP 请求报文的 cookie 首部行;
-
用户端系统中保留一个 cookie 文件;
-
位于 Web 站点的一个后端数据库。
1.4 Web 缓存
Web 缓存又称代理服务器,如本地浏览器缓存,请求过程如下:
-
浏览器创建一个到 Web 缓存器的 TCP 连接,并向 Web 缓存器中的对象发送一个 HTTP 请求;
-
Web 缓存器进行检查,看看本地是否存储该对象副本,如果有,Web 缓存器向客户返回该对象;
-
如果缓存器中没有该对象,它打开一个与该对象的初始服务器的 TCP 连接,Web 缓存器向初始服务器发送请求,并得到初始服务器的响应;
-
当 Web 缓存器接受对象后,在本地创建给对象的副本,并向客户发送响应报文返回该对象。
1.5 DNS
域名系统(Domain Name System)的主要任务:主机名到 IP 地址转换的目录服务。
2 传输层
2.1 UDP
2.1.1 UDP 报文段结构
-
源端口号:16 位;
-
目的端口号:16 位;
-
长度:16 位,报文段的总长度;
-
检验和:16 位,报文段中所有 16 位字的和进行反码运算;
-
应用数据:应用层的报文。
假定所有 16 位字的和为 0100101011000010,反码运算结果则为 1011010100111101,接收方相加应得到全部为 1;若这些之一是 0,则判断分组出现差错。
2.2 可靠数据传输原理
2.2.1 rdt
rdt1.0
发送端
- 等待上层调用,通过
rdt_send(data)接受高层数据分组发送,等待下一次调用。
接收端
- 等待下层调用,通过
rdt_rcv(packet)从底层接受分组传至高层,等待下一次调用。
rdt2.0(停等协议)
发送端
-
等待上层调用
rdt_send(data); -
等待 ACK 或 NAK,若
rdt_rcv(rcvpkt)&&isNAK(rcvpkt)则重新发送,若rdt_rcv(rcvpkt)&&isACK(rcvpkt)则等待下一次调用。
接收端
- 等待下层调用,若
rdt_rcv(rcvpkt)&&corrupt(rcvpkt)则发送 NAK,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)则发送 ACK 并将数据传至高层,等待下一次调用。
rdt2.1 (组序号)
发送端
- 等待上层调用 0,
rdt_send(data); - 等待 ACK 或 NAK 0,若
rdt_rcv(rcvpkt)&&(corrupt(rcvpkt)||isNAK(rcvpkt))则重新发送,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&isACK(rcvpkt)则等待下一次调用 1; - 等待上层调用 1,
rdt_send(data); - 等待 ACK 或 NAK 1,若
rdt_rcv(rcvpkt)&&(corrupt(rcvpkt)||isNAK(rcvpkt))则重新发送,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&isACK(rcvpkt)则等待下一次调用 0。
接收端
- 等待下层调用 0,若
rdt_rcv(rcvpkt)&&corrupt(rcvpkt)则发送 NAK,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&has_seq0(rcvpkt)则发送 ACK 将数据传至高层并等待下一次调用 1,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&has_seq1(rcvpkt)则发送 ACK 并继续等待调用 0; - 等待下层调用 1,若
rdt_rcv(rcvpkt)&&corrupt(rcvpkt)则发送 NAK,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&has_seq1(rcvpkt)则发送 ACK 将数据传至高层并等待下一次调用 0,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&has_seq0(rcvpkt)则发送 ACK 并继续等待调用 1。
rdt2.2(去除 NAK)
发送端
- 等待上层调用 0,
rdt_send(data); - 等待 ACK 0,若
rdt_rcv(rcvpkt)&&(corrupt(rcvpkt)||isACK(rcvpkt,1))则重新发送,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&isACK(rcvpkt,0)则等待下一次调用 1; - 等待上层调用 1,
rdt_send(data); - 等待 ACK 1,若
rdt_rcv(rcvpkt)&&(corrupt(rcvpkt)||isNAK(rcvpkt,0))则重新发送,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&isACK(rcvpkt,1)则等待下一次调用 0。
接收端
- 等待下层调用 0,若
rdt_rcv(rcvpkt)&&(corrupt(rcvpkt)||has_seq1(rcvpkt))则发送 ACK 1 继续等待调用 0,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&has_seq0(rcvpkt)则发送 ACK 0 将数据传至高层并等待下一次调用 1; - 等待下层调用 1,若
rdt_rcv(rcvpkt)&&(corrupt(rcvpkt)||has_seq0(rcvpkt))则发送 ACK 0 继续等待调用 1,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&has_seq1(rcvpkt)则发送 ACK 1 将数据传至高层并等待下一次调用 0。
rdt3.0 (比特交替协议)
发送端
- 等待上层调用 0,
rdt_send(data),开启定时器; - 等待 ACK 0,若
rdt_rcv(rcvpkt)&&(corrupt(rcvpkt)||isACK(rcvpkt,1))或超时则重新发送,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&isACK(rcvpkt,0)则等待下一次调用 1,停止计时; - 等待上层调用 1,
rdt_send(data),开启定时器; - 等待 ACK 1,若
rdt_rcv(rcvpkt)&&(corrupt(rcvpkt)||isNAK(rcvpkt,0))或超时则重新发送,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&isACK(rcvpkt,1)则等待下一次调用 0,停止计时。
接收端
- 等待下层调用 0,若
rdt_rcv(rcvpkt)&&(corrupt(rcvpkt)||has_seq1(rcvpkt))则发送 ACK 1 继续等待调用 0,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&has_seq0(rcvpkt)则发送 ACK 0 将数据传至高层并等待下一次调用 1; - 等待下层调用 1,若
rdt_rcv(rcvpkt)&&(corrupt(rcvpkt)||has_seq0(rcvpkt))则发送 ACK 0 继续等待调用 1,若rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)&&has_seq1(rcvpkt)则发送 ACK 1 将数据传至高层并等待下一次调用 0。
2.2.2 流水线传输协议
利用率 $$U=\frac{\frac{L}{R}}{\text{RTT}+\frac{L}{R}} $$ 其中 RTT(Round-Trip Time)指往返时延。
GBN(滑动窗口协议)
-
GBN 采用累计确认方式,数据必须按序交付,只要是在发送方超时时间之内成功接到了接收方返回的一串应答中的最后一个,则包含了前面全部的确认信息;
-
发送方会在分组丢失时回退 N 步重新发送;
-
接收方会丢弃所有失序分组。
SR(选择重传协议)
-
SR 采用逐个确认方式,窗口长度不超过序号空间大小的一半,否则无法区分是重传还是新数据;
-
发送方通过超时判定分组是否丢失;
-
接收方将确认一个正确接收的分组而不管是否按序,失序的分组将被缓存直到所有序号更小的分组都被收到,窗口才会移动;
2.3 TCP
2.3.1 TCP 报文段结构
-
源端口号:16 位;
-
目的端口号:16 位;
-
序号:32 位,即 Seq;
-
确认号:32 位,即 ACK;
-
首部长度:4 位,表明 TCP 首部长度;
-
标志字段:6 位,SYN 用于建立 TCP 连接,FIN 用于释放 TCP 连接,RST 用于重置 TCP 连接,ACK 用于确认TCP报文段是否被正常接收到,PSH 用于要求对方立即传输数据,URG 表示该段数据是紧急数据;
-
接受窗口:16 位,用于流量控制;
-
因特网检验和:16 位;
-
紧急数据指针:16 位;
-
选项:可选与变长;
-
数据:应用层的报文。
2.3.2 TCP 可靠数据传输
建立连接-三次握手
-
客户端向服务端发送 SYN 报文(SYN J),其中 J 表示客户端的初始序列号和选项;
-
服务端收到 SYN 报文后,需要确认客户端数据发送的 SYN 报文,向客户端返回 ACK 报文(ACK J+1),表示已经收到数据,并对客户端发送的序列号加 1 作为确认号;此时同时也向客户端发送一个 SYN 报文(SYN K),其中 K 表示服务端的初始序列号和选项;
-
客户端收到服务端回复的数据包后,需要向服务端发送确认报文(ACK K+1),表示已经收到服务端的 SYN 报文,并对服务端发送的序列号加 1 作为确认号。
服务端收到客户端的确认数据包后,连接建立成功,可以开始传输数据。
传输数据
断开连接-四次挥手
-
客户端发送一个 TCP 连接释放报文段(FIN),该报文段包含客户端曾经传递的序列号,向服务器请求断开连接;
-
服务器接收到连接释放报文段后,向客户端发送一个确认报文段(ACK),表示同意断开连接;
-
服务器已经没有数据要传输给客户端时,发送一个连接释放报文段(FIN),该报文段同样包含服务器曾经传递的序列号,向客户端请求断开连接;
-
客户端接收到服务器的连接释放报文段后,向服务器发送一个确认报文段(ACK),表示已经收到请求断开连接的报文,双方取消连接,四次挥手完成。
2.3.3 TCP 流量控制与拥塞控制
流量控制
接收方的 rwnd=0 时,发送方停止发送数据。
拥塞控制
慢启动:cwnd 从 1 个 MSS (最大报文段长度) 开始,每经过 1 个 RTT 将拥塞窗口增加一个 MSS,发送速率指数增长,直到拥塞;此时将慢启动阈值 ssthresh 设置为 cwnd/2,到达 ssthresh 后采用线性增长,如此循环往复。
3 网络层
3.1 网络层概述
3.1.1 转发与路由选择
数据平面是网络设备中负责实际数据传输的部分,由硬件实现识别和处理从输入端口进入设备的数据包,并将它们转发到正确的输出端口;
控制平面是网络设备中负责路由选择和决策的部分,由软件实现根据路由选择算法计算出最佳的路径,并将路由信息传递给数据平面;
转发表采取最长前缀匹配规则,即在该表中寻找最长的匹配项,向与最长前缀匹配相关联的链路接口转发分组。
3.2 网际协议
3.2.1 IPv4 数据报格式
-
版本号:4 位,决定是 IPv4 还是 IPv6;
-
首部长度:4 位,表示 IP 数据报的首部长度;
-
服务类型:8 位,Type of Service(TOS) 现已弃用;
-
数据报长度:16 位,表示 IP 数据报的总长度;
-
标识:16 位,与 IP 分片有关;
-
标志位:3 位,包括 DF(Don't Fragment),MF(More Fragments),Reserved,DF=1 表明不允许分片,MF=1 表明已进行了分片,IPv4 的 Reserved=0;
-
片偏移:13 位,表明当前分片数据的第一个字节在原始数据的位置除以 8,因为数据长度最多为 16 位,片偏移只有 13 位,相差 8 倍;
-
寿命:8 位,每经过一次路由器处理,寿命减 1;
-
上层协议:8 位,表明使用哪一个运输层协议,如 TCP 和 UDP;
-
首部检验和:16 位,首部每 2 个字节作为 1 个数反码求和;
-
源 IP 地址:32 位,
-
目的 IP 地址:32 位,
-
选项:首部的扩展,非必需;
-
数据:承载的数据。
3.2.2 IP 切割与重组
切割:切割的数据报继承 16 位标识号,MF 和片偏移值变化,算法如下:
假定原始数据 1110 字节,每段不超过 512 字节 (最大传输单元 MTU),应划分为 488+488+134,除最后一段分片必须为 8 的倍数。
重组:重组仅发生在最终接收方,算法如下:
将各个分片按照偏移量从低到高依次排列,然后去掉每个分片中的IP头部,将数据部分拼接起来得到原始数据报。
3.2.3 IPv4 编址
IPv4 由 x 位子网地址(网络号),32-x 位主机地址(主机号)组成。
- A 类地址是 1.0.0.0 到 126.0.0.0 的地址,用于大型网络 (高位 0,网络号 8 位,主机号 24 位);
- B 类地址是 128.0.0.0 到 191.255.0.0 的地址,用于中等规模的网络 (高位 10,网络号 16 位,主机号 16 位);
- C 类地址是 192.0.0.0 到 223.255.255.0 的地址,用于小规模的网络 (高位 110,网络号 24 位,主机号 8 位);
- D 类地址是 224.0.0.0 到 239.255.255.255 的地址,用于多播(高位 1110,主机号 28 位);
- E 类地址是 240.0.0.0 到 247.255.255.255 的地址,保留用于将来使用 (高位 11110)。
网络号的计算方法:
假定 IPv4 地址为 192.168.1.100,子网掩码为 255.255.255.0,换算为 11000000.10101000.00000001.01100100 和 11111111.11111111.11111111.00000000,按位与运算得到 192.168.1.0/24 即网络号。
使用子网掩码可以提高地址的利用率,格式为高位 1 低位 0,1 的个数即网络号长度。