公司开了个极客时间企业版,一人挑五门课

看了下这个《趣谈网络协议》挺有意思的

只看了前两讲就感觉收获挺大,所以记记笔记方便以后查找知识

通信协议综述

协议三要素

  • 语法: 符合一定的规则和格式。例如括号要成对,换行要有分号。
  • 语义: 代表某种意义。例如数字可以相间,字符串相减没有意义。
  • 顺序: 就是先干什么后干什么。例如 1+1-1 就是 先执行 1+1 在用结果减 1。

网络协议和层级

层级 协议
应用层 DHCP HTTP HTTPS RTMP P2P DNS GTP RPC
传输层 (TCP/UDP 层) UPD TCP
网络层 (IP层) ICMP IP OSPF BGP IPSec GRE
链路层 (MAC层) ARP VLAN STP
物理层 网络跳线

当网络包到达一个城关的时候,可以通过路由表得到下一个城关的 IP 地址,直接通过 IP 地址找就可以了,为什么还要通过本地的 MAC 地址呢?

  1. mac地址 相当于身份证号(网卡厂商分配,理论上是唯一的但可以被修改),ip地址 相当于现居住地(连接到网络时,网络运营商分配)。
  2. 历史原因,网络发展史是先有 数据链路层(MAC地址) 再有 网路层(IP地址) 的。
  3. 网络分层,只要是在网络上跑的包,都是完整的。可以有下层没上层,绝对不可能有上层没下层。也就是说在网络分层的角度 数据包不可能只有IP地址没有MAC地址

为什么要网络分层?

复杂的程序都要分层,这是程序设计的要求。比如,复杂的电商还会分数据库层、缓存层、Compose 层、Controller 层和接入层,每一层专注做本层的事情。

img

ip地址

如何查看ip地址?

  • windows:ipconfig
  • linux:ifconfig 和 ip addr

ip地址的组成?

10.100.122.2 就是一个 IP 地址。这个地址被点分隔为四个部分,每个部分 8 个 bit,所以 IP 地址总共是 32 位。

ip地址被分为五类

IP地址范围 最大主机数 私有IP地址范围
A类 0丨网络号(7位)丨主机号(24位) 0.0.0.0 - 127.255.255.255 16777214 10.0.0.0 - 10.255.255.255
B类 10丨网络号(14位)丨主机号(16位) 128.0.0.0 - 191.255.255.255 65534 172.16.0.0 - 172.31.255.255
C类 110丨网络号(21位)丨主机号(16位) 192.0.0.0 - 223.255.255.255 254 192.168.0.0 - 192.168.255.255
D类 1110丨多播组号(28位)
E类 11110丨留待后用(27位)

无类型域间选路(CIDR)

由于 C 类地址包含的最大主机数太少,只有 254个。而 B 类地址包含主机数又太多。

所以有了一种折中的方式叫 无类型域间选路,简称 CIDR

CIDR 将 32 位IP地址一分为二,前面是网络号,后面是主机号。

比如 10.100.122.2/24,这个IP地址有一个斜杠,斜杠后的 24 代表前24位是网络号,后8位是主机号。

伴随 CIDR 存在的是广播地址子网掩码

  • 10.100.122.2/24 的广播地址是 10.100.122.255
  • 10.100.122.2/24 的子网掩码是 255.255.255.0

子网掩码IP地址进行按位与运算就可以得到网络号

  • 10.100.122.2 按位与 255.255.255.0 就是 10.100.122.0

计算 CIDR 表示的 IP地址 16.158.165.91/22 的第一个地址、子网掩码 和 广播地址。

  • 第一个地址是 16.158.<101001><00>.1 即 16.158.164.1
  • 子网掩码是 255.255.<111111><00>.0 即 255.255.252.0
  • 广播地址是 16.158.<101001><11>.255 即 16.158.167.255

小结

  • IP 是地址,有定位功能;MAC 是身份证,无定位功能
  • CIDR 可以用来判断是不是本地人
  • IP 分公有的 IP 和私有的 IP

DHCP 和 PXE

如何获取目标MAC地址?

  1. linux 会判断目标IP地址是一个网段的吗,或者和我的一个网卡是同一网段的吗?如果是一个网段的,会发送 ARP 请求,获取MAC地址。
  2. 如果不是,linux 会认为这个一个跨网关调用,会获取网关MAC地址,然后将包发到网关。
  3. 每经过一个网关,MAC地址都会被替换下一次要去的网关的MAC地址,直到到达和目标IP地址同网段的网关时,发送 ARP请求获取目标IP的主机 MAC 地址。

DHCP 的工作方式

  1. 当一台新机器假如网络时,只知道自己的 MAC地址,先”吼”一句告诉别人我来了。这一步称为 DHCP Discover

    • 新来的机器使用 IP地址 0.0.0.0 发送一个广播包,目的IP为 255.255.255.255
    • 广播包封装了 UDP,UDP封装了BOOTP
    img
  2. 如果网络管理员配置了 DHCP Server的话,它就会立刻知道来了”新人”,这时候会验证 MAC地址的唯一性,并且租给新人一个IP地址。这个过程我们称为 DHCP Offer

    • DHCP Server 会保留为该”新人”分配的IP地址,防止分配给其他人

    • DHCP Server仍然使用广播地址作为目的地址,因为”新人”还没有IP地址

    img
  3. 新来的机器收到了 “吼”的回复,并且如果同时收到多个 DHCP Server的回复,它会决定使用谁提供的IP地址,一般是第一个回复的,并且告诉其它 DHCP服务,请求它们撤销提供的IP地址,以便可以分配给其他人。

    • 由于还没有得到 DHCP Server 的最后确认,客户端仍然使用 0.0.0.0 为源 IP 地址、255.255.255.255 为目标地址进行广播。
  4. 当 DHCP Server 接收到新来的机器的 DHCP request 之后,会广播返回给它一个 DHCP ACK 消息包,表明已经接受客户机的选择,并将这一 IP 地址的合法租用信息和其他的配置信息都放入该广播包,发给客户机,欢迎它加入网络大家庭。

    img

PXE(预启动执行环境)工作过程

可以自动安装操作系统。

ps: 了解一下工作过程就行了。。

img

从2层(MAC层)到3层(网络层)

从物理层到链路层

物理层

  • 电脑连电脑。
  • 集线器。

数据链路层(MAC层)

数据链路层其实包含:

  • LLC(The logical link control),逻辑控制链路
  • MAC(Medium Access Control),媒体访问控制

由于TCP/IP 体系经常使用的局域网是 DIX Ethernet V2而不是 IEEE 802 标准中的几种局域网,因此现在 802 委员会制定的逡辑链路控制子层 LLC (即 802.2 标准)的作用已经不大了。

很多厂商生产的网卡上就仅装有 MAC 协议而没有 LLC 协议

所以一般不考虑 LLC 层,只考虑MAC层。

主要解决这几个问题:

  1. 这个包是发给谁的?谁应该接收?
    • 这里用到一个物理地址,叫作链路层地址。但是因为第二层主要解决媒体接入控制的问题,所以它常被称为MAC 地址
  2. 大家都在发,会不会产生混乱?有没有谁先发、谁后发的规则?
    • 信道划分:分多个车道,每个车一个车道,你走你的我走我的
    • 轮流协议:今天单号,明天双号,轮流出行
    • 随机接入协议:不管三七二十一,有事儿先出门,发现特堵,就回去,错过高峰再出。以太网就是这个方式。
  3. 如果发送的时候出现了错误,怎么办?
    • CRC(循环冗余检测):通过 XOR 异或的算法,来计算整个包是否在发送的过程中出现了错误

ARP协议

ARP协议是一个网络层协议,也就是已知 IP 地址,求 MAC 地址的协议。

原理是发送广播包,目标IP回答。

为避免每次都是用ARP请求,机器会进行ARP缓存(ARP缓存表),并且该缓存会有过期时间。

交换机

交换机一般工作在 数据链路层(MAC层)

交换机可以通过学习记录连接某个口的MAC地址。交换机的学习结果称为转发表,并且有过期时间。

一台 MAC1 电脑将一个包发送给另一台 MAC2 电脑,当这个包到达交换机的时候,一开始交换机也不知道 MAC2 的电脑在哪个口,所以没办法,它只能将包转发给除了来的那个口之外的其他所有的口。但是,这个时候,交换机会干一件非常聪明的事情,就是交换机会记住,MAC1 是来自一个明确的口。以后有包的目的地址是 MAC1 的,直接发送到这个口就可以了。

RARP协议

根据MAC地址获取IP的协议。。知道就行了。。

如果一个局域网里面有多个交换机,ARP 广播的模式会出现什么问题呢?

ARP广播时,交换机会将一个端口收到的包转发到其它所有的端口上。
比如数据包经过交换机A到达交换机B,交换机B又将包复制为多份广播出去。
如果整个局域网存在一个环路,使得数据包又重新回到了最开始的交换机A,这个包又会被A再次复制多份广播出去。
如此循环,数据包会不停得转发,而且越来越多,最终占满带宽,或者使解析协议的硬件过载,行成广播风暴。

交换机与VLAN

拓扑结构是如何形成的

假设现在两台交换机,连接着三个局域网,机器1想要访问机器4,但是机器1只知道机器4的IP地址,不知道MAC地址。

img
  1. 机器1发起一个广播,机器2收到广播,但跟自己没关系。
  2. 交换机A也收到了广播,但是它不知道任何拓扑信息,于是它向除了广播包的来源方向外,转发给其它所有网口。
  3. 机器3收到了广播信息,发现也不是找自己的。
  4. 交换机B收到广播后,采用交换机A相同操作。
  5. 机器4和机器5也收到广播,机器4发现是找自己的(IP地址一致),于是响应说这是找我的。
  6. 最后,交换机A和交换机B现在都知道机器1是左边这个网口的。
  7. 如果这时机器3需要访问机器1,交换A和交换机B就不会再广播右边的网口了。

如何解决环路问题

  1. STP协议就是使用最小生成树的思想。关于最小生成树可以看我之前分享的:Kruskal算法
  2. 物理隔离虚拟隔离(VLAN形成虚拟局域网隔离)

ICMP和ping

ICMP协议

ICMP 全称 Internet Control Message Protocol,就是互联网控制报文协议

ICMP是一个网络层协议。

类型值 ICMP消息类型 错误消息 查询消息
0 Echo Reply
回送响应消息
3 Destination Unreachable
目的不可达
5 Redirect
重定向
8 Echo Request
回送请求消息
11 Time Exceeded
超时
12 Parameter Problem
参数问题
13 Timestamp Request
时间戳请求
14 Timestamp Reply
时间戳响应

ping

ping是ICMP最著名的一个应用,可以测试 网络的可达性

img

tracert

ping 工具只能测试目的设备的连通性,但是看不到数据包的传输路径

tracert 工具可以查看数据包的整条传输路径,包括途中经过的中间设备

IP 头部的 TTL 字段是为避免数据包循环转发而设计的。每经过一个路由器,数据包头中的 TTL 值减 1 。如果 TTL 值为 0 则丢弃报文,并向源设备回应一个 Time Exceeded 消息,告知错误类型。

使用 tracert 命令时,源设备的 tracert 逐跳发送数据包,并等待每一个响应报文。发送第一个数据包时,TTL 值设为 1 。第一个路由器收到数据包后 TTL 值减 1 ,随即丢弃数据包,并返回一个 Time Exceeded 消息。

怎么知道 UDP 有没有到达目的主机呢?Traceroute 程序会发送一份 UDP 数据报给目的主机,但它会选择一个不可能的值作为 UDP 端口号(大于 30000)。当该数据报到达时,将使目的主机的 UDP 模块产生一份“端口不可达”错误 ICMP 报文。如果数据报没有到达,则可能是超时。

网关

一台机器访问另一个ip地址

  1. 先判断 目标IP和当前机器的IP地址,是不是一个网段的。
  2. 如果是一个网段的,那就使用ARP协议获取目标IP的MAC地址。没网关什么事情。
  3. 如果不是同一网段的,那请求就要发往默认网关(通过ARP协议获取网关MAC地址)。

IP 头和 MAC 头哪些变、哪些不变?

静态路由: IP不变,MAC地址变。

NAT(Network Address Translation)路由:IP变,MAC地址变。

传输层

UDP协议

UDP包头

img

UDP和TCP的区别

面向连接

什么是连接?连接其实就是 客户端和服务端建立一个数据结构来维护双方交互状态。

  • TCP是面向连接的
  • UDP是面向无连接的
可靠性

IP包是没有任何可靠性保证的,一旦发出去,不管是超时了还是丢了,都随它而去

  • TCP提供可靠交付,通过 TCP 连接传输的数据,无差错、不丢失、不重复、并且按序到达
  • UDP 继承了 IP 包的特性,不保证不丢失,不保证按顺序到达
面向字节流

IP包不是流,而是一个个的IP包。

  • TCP是面向字节流的,发送的是一个流,没头没尾
  • UDP发送是基于数据包的,一个个的发,一个个的收
  • 所以TCP会发生粘包和拆包,而UDP不会

ps: 粘包和拆包是一个通俗的说法,在知乎上会被很多大佬喷成是伪命题、伪科学。这里我们知道原理就行了。

拥塞控制
  • TCP意识到包丢弃了或者网络环境不好了的时候,会根据情况调整自己的行为,看看是不是发快了,要不要发慢点
  • UDP则不会

如果 MAC 层定义了本地局域网的传输行为,IP 层定义了整个网络端到端的传输行为,这两层基本定义了这样的基因:网络传输是以包为单位的,二层叫帧网络层叫包传输层叫段。我们笼统地称为包。包单独传输,自行选路,在不同的设备封装解封装,不保证到达。基于这个基因,生下来的孩子 UDP 完全继承了这些特性,几乎没有自己的思想。

UDP的特点

  • 沟通简单:UDP的包头比起TCP来说相当简单
  • 轻信他人:UDP不需要建立连接,谁都可以给它发送数据,它也可以传给任何人数据
  • 愣头青:不会根据网络的情况进行发包的拥塞控制,无论网络丢包丢成啥样了,它该怎么发还怎么发。

TCP协议

TCP包头

img

TCP的三次握手

tcp是面向连接的,双方都需要维护一个状态机,三次握手状态变化时序图:

img
  1. 一开始,客户端和服务端都处于 CLOSED 状态
  2. 服务端主动监听某个端口,处于 LISTEN 状态
  3. 客户端发起连接发送 SYN,之后客户端处于 SYN_SENT 状态
  4. 服务端收到 SYN包后,应答发送 SYN + ACK 包,之后服务端处于 SYN_REVD状态
  5. 客户端收到 SYN + ACK 后应答发送 ACK 包, 客户端处于 ESTABLISHED 状态,因为客户端已经完成了一次发送一次接收
  6. 服务端收到 ACK后,也处于 ESTABLISHED 状态,它也完成了一次发送,一次接收

TCP的四次挥手

img
  1. 一开始,客户端和服务端都处于 ESTABLISHED 状态
  2. 客户端:我不玩了。发送 FIN 包并进入 FIN_WAIT_1 状态
  3. 服务端:我知道你不玩了。发送 ACK 包,进入等待关闭 CLOSED_WAIT 状态
  4. 客户端:我知道了。收到 ACK 包,进入 FIN_WAIT_2 状态
    • 如果服务端在这个时候跑路了,客户端将永远处于这个状态
  5. 服务端:我这边处理完了,我也不玩了。 发送 FIN+ACK 包,进入 LAST_ACK 状态
  6. 客户端:我知道你不玩了。发送 ACK 包,进入 TIME_WAIT 状态
    • 这里的 TIME_WAIT 时间要足够长,长到如果服务端没有收到这次的 ACK 包的话,会重复第五步,重发 FIN+ACK 包
    • 等待的时间设为 2MSL,MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃
  7. 服务端收到客户端最后一个 ACK 包后,进入 CLOSED 状态
  8. 客户端在 TIME_WAIT 时间过了之后,进入CLOSED 状态

TCP状态机

将连接建立和连接断开的两个时序状态图综合起来,就是这个著名的 TCP 的状态机。

img

在这个图中,加黑加粗的部分,是上面说到的主要流程,其中阿拉伯数字的序号,是连接过程中的顺序,而大写中文数字的序号,是连接断开过程中的顺序。加粗的实线是客户端 A 的状态变迁,加粗的虚线是服务端 B 的状态变迁。

小结

TCP 包头很复杂,但是主要关注五个问题,顺序问题,丢包问题,连接维护,流量控制,拥塞控制。

连接的建立是经过三次握手,断开的时候四次挥手

TCP 的连接有这么多的状态,如何在系统中查看某个连接的状态吗?

linux中可以使用 netstat 命令

套接字Socket

基于TCP

在内核中,为每个 Socket 维护两个队列。一个是已经建立了连接的队列,这时候连接三次握手已经完毕,处于 established 状态;一个是还没有完全建立连接的队列,这个时候三次握手还没完成,处于 syn_rcvd 的状态。

工作过程:

  • 服务端和客户端初始化 socket,得到文件描述符;
  • 服务端调用 bind,将绑定在 IP 地址和端口;
  • 服务端调用 listen,进行监听;
  • 服务端调用 accept,等待客户端连接;
  • 客户端调用 connect,向服务器端的地址和端口发起连接请求;
  • 服务端 accept 返回用于传输的 socket 的文件描述符;
  • 客户端调用 write 写入数据;服务端调用 read 读取数据;
  • 客户端断开连接时,会调用 close,那么服务端 read 读取数据的时候,就会读取到了 EOF,待处理完数据后,服务端调用 close,表示连接关闭。

这里需要注意的是,服务端调用 accept 时,连接成功了会返回一个已完成连接的 socket,后续用来传输数据。

所以,监听的 socket 和真正用来传送数据的 socket,是「两个」 socket,一个叫作监听 socket,一个叫作已完成连接 socket

成功连接建立之后,双方开始通过 read 和 write 函数来读写数据,就像往一个文件流里面写东西一样。

基于UDP

对于 UDP 来讲,过程有些不一样。UDP 是没有连接的,所以不需要三次握手,也就不需要调用 listen 和 connect。

但是,UDP 的交互仍然需要 IP 和端口号,因而也需要 bind。UDP 是没有维护连接状态的,因而不需要每对连接建立一组 Socket,而是只要有一个 Socket,就能够和多个客户端通信。

也正是因为没有连接状态,每次通信的时候,都调用 sendto 和 recvfrom,都可以传入 IP 地址和端口。

img

应用层

HTTP协议

http请求格式

img

http请求过程

  1. DNS解析:域名解析为IP地址。
  2. http 是基于 tcp协议的,请求前需要先通过三次握手建立连接,如果开启了 keep-alive,该连接就可以多次复用。
    • http1.1 是默认开启 keep-alive的
    • keep-alive 也有超时时间,超时关闭之后,后面需要的http请求需要重新建立连接
  3. tcp层,拼接源和目标端口。
  4. ip层,拼接源和目标IP地址。
    • 如果网段相同,通过arp协议获取mac地址,直接发送
    • 否则通过arp协议获取网关mac地址,发送给网关
  5. mac层,拼接mac地址。

tcp报文段:

http响应格式

img

HTTPS协议

  • 对称加密:加密和解密用的密钥相同。优点是效率高、性能好。
  • 非对称加密:加密和解密的密钥不同,一般是一个公钥一个私钥。效率比较低。
  • CA( Certificate Authority):一个权威的颁发证书的机构,证书里有公钥等信息。最高级的ca机构成为 root CA。

https协议握手过程:

这里老师讲的感觉有点不太清晰,推荐这篇文章:http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html

  • 客户端->服务端:给出协议版本号、一个客户端生成的随机数(Client random)、以及客户端支持的加密方法。
  • 服务端->客户端:服务端选取确认双方使用的加密方法、给出数字证书、以及一个服务端生成的随机数(Server random)。
  • 客户端->服务端:客户端验证数字证书是否有效,生成一个随机数(Premaster secret),并使用约定的加密方法和公钥加密这个随机数。
  • 服务端:使用自己的私钥,解密获取上一步客户端发过来的随机数(Premaster secret)。
  • 之后,双方使用约定的加密方法和前面的三个随机数,生成“对话密钥”(session key),用来对称加密接下来的对话。

陌生的数据中心

DNS协议

DNS服务器

img

DNS解析流程

  1. 电脑客户端会发出一个 DNS 请求,问 www.163.com 的 IP 是啥啊,并发给本地域名服务器 (本地 DNS)。那本地域名服务器 (本地 DNS) 是什么呢?如果是通过 DHCP 配置,本地 DNS 由你的网络服务商(ISP),如电信、移动等自动分配,它通常就在你网络服务商的某个机房。
  2. 本地 DNS 收到来自客户端的请求。你可以想象这台服务器上缓存了一张域名与之对应 IP 地址的大表格。如果能找到 www.163.com,它就直接返回 IP 地址。如果没有,本地 DNS 会去问它的根域名服务器:“老大,能告诉我 www.163.com 的 IP 地址吗?”根域名服务器是最高层次的,全球共有 13 套。它不直接用于域名解析,但能指明一条道路。
  3. 根 DNS 收到来自本地 DNS 的请求,发现后缀是 .com,说:“哦,www.163.com 啊,这个域名是由.com 区域管理,我给你它的顶级域名服务器的地址,你去问问它吧。”
  4. 本地 DNS 转向问顶级域名服务器:“老二,你能告诉我 www.163.com 的 IP 地址吗?”顶级域名服务器就是大名鼎鼎的比如 .com、.net、 .org 这些一级域名,它负责管理二级域名,比如 163.com,所以它能提供一条更清晰的方向。
  5. 顶级域名服务器说:“我给你负责 www.163.com 区域的权威 DNS 服务器的地址,你去问它应该能问到。”
  6. 本地 DNS 转向问权威 DNS 服务器:“您好,www.163.com 对应的 IP 是啥呀?”163.com 的权威 DNS 服务器,它是域名解析结果的原出处。为啥叫权威呢?就是我的域名我做主。
  7. 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。
  8. 本地 DNS 再将 IP 地址返回客户端,客户端和目标建立连接。
img

负载均衡

某个应用要访问另外一个应用,如果配置另外一个应用的 IP 地址,那么这个访问就是一对一的。但是当被访问的应用撑不住的时候,我们其实可以部署多个。但是,访问它的应用,如何在多个之间进行负载均衡?只要配置成为域名就可以了。在域名解析的时候,我们只要配置策略,这次返回第一个 IP,下次返回第二个 IP,就可以实现负载均衡了。

CDN

CDN分发系统架构

CDN 系统的缓存,也是一层一层的,能不访问后端真正的源,就不打扰它。这也是电商网站物流系统的思路,北京局找不到,找华北局,华北局找不到,再找北方局。

img