网络应用协议 & 网络分层模型 & 设计原则

注意
本文最后更新于 2024-07-22,文中内容可能已过时。

CS114 课程的课程笔记

网络应用协议 & 网络分层模型 & 设计原则

万维网使用 HTTP (Hypertext Transfer Protocol) 通信。

在 HTTP 中,客户端打开到服务器的连接并发送命令

BitTorrent 是一种允许人们共享大文件的程序。

不同于 Web,BitTorrent 中是客户端像其他客户端申请。BitTorrent 将文件分为称为 pieces 的数据块,一个客户端从另一个客户端下载了一个块后,它会告诉其他客户端自己拥有这个块,这种协作的客户端的集合被称为群集(swarms)。

当用户想要下载某个文件时,他需要先下载 torrent 文件(这通常是通过互联网找到的),这个 torrent 文件描述了要下载的文件的相关信息,还有这个 torrent 的 tracker 信息(tracker 是一个保持 track 群集的成员的节点)。

加入一个 torrent,自己这个客户端会连接到 tracker,并请求其他客户端的列表,本机就会尝试连接到其他客户端并开始下载文件

简单情况下就是客户端A和客户端B都能互相访问,那么也没什么可做的。

如果引入了 NAT (Network Address Translator,就像无线路由器就是NAT) 就会复杂一些。自己的设备会在 NAT 的后面,这就导致自己的设备可以通过 NAT 连接互联网,但互联网上的设备不能直接访问到自己的设备。

假设 B 在 NAT 后方,那么 A 就无法直接连接 B。

Skype 通过使用一种被称为 Rendezvous 服务器的东西解决了这个问题。

一开始 A 和 B 都会和 Rendezvous 服务器建立连接,当 A 想要连接 B 的时候,这个请求会通过 Rendezvous 服务器发送到B这里,如果B同意就由 B 尝试连接到 A。这里被称为反向连接。

如果 A 和 B 都在 NAT 后面,Skype 通过使用 Relay 服务器处理这个情况。

/img/CS144/network_layer_4.png

整个互联网本身就由主机,链接和路由组成,数据以数据包的形式在每个链接中跳转传递。数据包包含数据和一段头部信息,这个信息包含数据包的来路和去向。

链路层的工作就是将数据在链接中不断的跳转。链路层的应用的例子就是以太网和 WiFi 等

网络层的工作是在互联网中将数据端对端的传送给对方。网络层的数据包(也叫数据报, datagram)的 header 会附带源地址和目标地址的信息。网络层会将数据包给链路层,让链路层通过第一个链接传递数据。链路层会将它跳到路由,路由的链路层接收到之后再传递给路由的网络层,这里的网络层会检查这个数据报的目标地址,并将其向目标地址跳一下。路由再传递到路由,直到到达目标地址。

链路层的具体实现方式并不是一种(例如以太网或 WiFi ),但网络层通过接口传递数据报,这种分离的效果使得网络层无需关注链路层的细节。

在网络层中,通过 Internet 传递数据就需要用到 IP 协议 (Internet Protocol)。

  • IP 尽可能尝试将数据报传递到目的地,但其本身并不保证这一点。
  • IP 数据报可能会丢失,传递不按顺序,也可能会损坏,它没有保证这些。

最常见的传输层的协议就是 TCP (Transmission Control Protocol)。TCP 确保了数据会以正确的顺序并传递过去,并且传输过程中数据报丢失了的话会重发。TCP 保证了运行在网络层之上的服务是的网络连接是可靠的。

相应的,有不保证顺序,也不会在丢失的时候重发的 UDP (User Datagram Protocol) 协议。UDP 只是将应用层的数据送到网络层。

常用的就是 TCP 和 UDP 了,但实际上还有其他的协议(比如 RTP )。

应用层就是常见的那些 http, smtp, ssh, ftp 之类的了。

/img/CS144/network_layer_4_7.png

当传输层需要传输数据的时候,传输层将数据发送到下一层——网络层。网络层会将数据放到 IP 数据报中,IP 的工作就是将它发送到另一端。IP 数据包需要通过链路层进行传输,所以它要将数据包发送给链路层,链路层将其放到数据帧(frame)中(例如以太网数据包),然后送到第一个路由器中。

IP 并不可靠,它不保证数据报一定到达,更不会保证到达的顺序,甚至在必要的时候会丢弃数据报(比如路由器中的数据报队列满了)。

这么设计是为了以下几点

  • 更加简单,容易维护,消费更低,速度更快。
  • 端到端原则:尽可能在端测主机实现功能,而不是在网络硬件中。
  • 允许顶层构建可能可靠或不可靠的服务。
  • 对下层的链路层要求更低,对链路层没有太多的假设条件。
  • IP 尝试阻止数据报永远循环。
    • 由于路由器转发表错误,可能导致数据报一直在循环发送。
    • 引入了 TTL 字段解决这个问题,TTL 每通过一个路由器都递减一次,如果到 0 了,就认为处于循环的状态,由路由器丢弃它。
  • IP 会对太长的数据报分段
    • IP 被设计为各种链路工作,不同链路对数据报大小的要求不一致。
      • 比如 Ethernet 携带的数据报长度不能超过 1500 字节。
    • IP 的 header 包含一些字段用于帮助路由器将一个数据报分开,并向对面主机提供信息需要重组数据。
  • IP 数据报 header 包含一个校验和字段,以确保数据报到达正确的位置。
  • IP 有两种版本
    • IPV4: 当前广泛使用,32 bit 的地址
    • IPV6: 128 bit 地址。
  • IP 允许新字段加入数据报 header 中。

/img/CS144/ipv4_datagram_header.png

  • Destination IP Address: 目标地址。
  • Source IP Address: 源地址。
  • Protocol ID: 数据字段的内容。允许目标主机对包解开并复用,如果 Portocal ID 是6,则该数据就包含一个 TCP 段。IANA 定义了 140+种不同的协议值。
  • Version: IP 当前的版本,V4 还是 V6。
  • Total Packet Length: 数据报总长度。
  • TTL: 防止数据报永远处于循环状态。
  • Packet ID, Flags, Fragment Offset: 帮助路由器将 IP 数据报分成小份。
  • Type of Service: 向路由器提示该数据报的重要性。
  • Header Length: header 的长度,帮助自定义 header 字段。
  • Checksum: 防止发送到错误的地方。

互联网四层模型中,从应用层获取数据流,传输层将其可靠地传递给另一台计算机上的应用程序。传输层将这些作为网络层数据包发送,网络层将其传递给另一台计算机。

客户端通过三次握手和服务器连接:

  1. 当客户端发送服务器一个 synchronize 信息,通常称为 SYN。
  2. 服务端收到 SYN 后,发送一个确认连接消息,通常称为 SYN-ACK。
  3. 客户端收到后,再回复一个确认信息 ACK。

为了标示将数据报传送给哪个应用程序,存在 TCP prot 用于标识。

客户端第一步跳到 WiFi 接入点,接入点存在一个 broader Ethernet 有线连接,所以数据报强制沿着线路跳。路由器连接很多链路,当数据报到达时,路由器决定将其发送到哪个链路。

路由器有 IP 地址,所以它可能不为了一个包,而是用自己的软件发送。例如使用 TCP 登录路由器时,IP 数据报将被发送到路由器自己的 IP 地址。这是通过转发表实现。

数据报到达后,路由器检查那个转发条目和数据报最匹配。

可以使用 Wireshark 验证这一过程。

/img/CS144/wireshark_demo.png


我认为现在没有什么网站是 HTTP 的了,我这里访问的是 BiliBili 所以三次握手后还有专属于 HTTPS 的 TLS 握手。

traceroute 可以 trace 数据包传递的每一跳的信息,但是貌似对方可以设置不回显,这样返回不了信息。


这是构建网络的常用做法。

独立每个到达的数据包,选择将其传出链路,如果该链路空闲就发送,否则保存并等待。

  1. 交换机可以为每个数据包单独做决定,不需要保留额外的数据包,它只需要负责转发。
    • 例如语音电话由多个连续的数据包组成,它们属于同一组通信,将这种数据包序列称为流 (flow)。
    • 由于各个数据包是独立的,所以交换机不需要处理整个流。
    • 交换机不需要担心添加或删除流的状态,交换机会在合适的时候完成转发。交换机不会存储状态信息,因为交换机必须快速,将该状态存储到高速内存中的代价昂贵。
    • 如果手机发出一个 web 请求后没电了,交换机将保存请求的 “per-flow state”,但如果其中一个节点创建状态失败后,交换机需要知道如何清除它,否则你可能面临被一堆流量占内存的情况。对于数据报切换来说,交换机不存储 “per-flow state”,如果手机没电了,交换机只会停止接收来自它的数据包。
    • 因此,交换机在功能上就独立于发送流量的计算机。
  2. 更有效的共享链接
    • 考虑到一点,用户使用的网络服务都是突发性的,不会以固定的频率发送和接收特定的数据。
    • 将所有流量都视作数据包,可以做到:假如 A 在阅读网页,B 在加载网页,路由器可以将A的容量都放B的数据包。如果 A 和 B 都在使用,那么路由器在二者之间共享。
    • 采取单一资源并以概率方式在多个用户之间共享的想法被称为统计复用。每个用户都会获得基于多少用户正在使用的资源的统计份额。例如 A 正在阅读,B 就可以使用所有的链路,如果两个人都在加载页面,那都得到一半的链路容量。

就是模块化,每层只为它的上层,抽象接口。

封装是将分层和数据报切换结合发生的结果。

发送一个数据包时,每个数据包都包含来自多个层的数据。例如 TCP 段位于 IP 数据包内,而 IP 数据包又会在以太网帧内。封装就是这个原则。

关于封装的数据包,有两种画法:

/img/CS144/datagram_gram_p1.png

第一种是硬件的视角,header 在右边,右边也是第一位,离开交换机的第一位是最右边的位。

/img/CS144/datagram_gram_p2.png

第二种是软件的视角,header 在左边,许多文档和协议都这么画,这么画的出发点是数据包的开头是地址0,而左边是地址0,所以 header 在左边。

VPN (Virtual Private Network)

当你与互联网通信并发送 IP 数据包而不是正常发送它们时,它们会被发送到 VPN 连接中,以便 IP 数据包到达私有网络内。

在这种路线中,HTTP 被 TCP 封装,TCP 被 IP 封装,IP 被 TLS 封装,而 TLS 再被 TCP 封装,这个 TCP 被 IP 封装。

外层的 TCP/IP 都是用于到达 VPN 网关而用,内部的 TCP/IP 用来访问具体的 web server。