<commit_before>---
layout:     post		
title:      "网络是怎样连接的"		
date:       2018-10-14	
author:     "KingXt"		
tags:
    - 网络
---

# 网络是怎样连接的

淘宝手机客户端浏览商品是怎么获取到服务器数据的？这里会衍生出以下一些问题。

<img src="/img/post/network-question.png" width="600"/>

上图一些列问题反映了很多知识点，接下来会一个一个通俗点描述其工作原理。

### 从下面三个方面可以更加有一个直观认识
> 1. 客户端要做的事情
> 2. 网络传输要做的事情
> 3. 服务器要做的事情


### 1. 客户端要做的事情

不管是手机客户端还是pc，客户端发送内容到服务器都需要经过下面几个过程:
> 1. 生成http请求消息
> 2. 向dns服务器查询服务器的ip地址
> 3. 委托协议栈发送消息，创建套接字Socket，发送数据，断开服务器连接

#### 1.1 生成http请求消息
Http请求消息是应用程序生成的，而且有一些第三方库很方便应用开发者生成请求消息内容，比如android应用程序可以用okhttp，ios应用程序可以用NSURLSession，go提供的net库等。但是http请求消息体都有其标准格式，如下图所示：

<img src="/img/post/network-request.png" width="600"/>

http请求消息生成之后，由于应用本身不具备将消息发送到网络功能，这需要将这个任务交给操作系统来实现，但是交给操作系统之前，比如要将域名解析为对应的IP地址。如果本来就是通过IP直接访问，那么这个步骤就省略了。

#### 1.2 向dns服务器查询服务器的ip地址

这里先介绍下IP地址是什么？ 如下图所示：

<img src="/img/post/network-ip.png" width="600"/>

主机号部分的比特全部为0或者全部为1时代表以下两种特殊的含义。
> 1. 主机号部分全部为0代表整个子网而不是子网中的某台设备。
> 2. 主机号部分全部为1代表向子网上所有设备发送包，即广播.

域名解析过程入下图www.lab.glasscom.com所示，肯定会先访问最近的一台DNS服务器，如果最近的DNS服务器没有存放域名对应信息。由于最近的DNS服务器没有存放www.lab.glasscom.com对应的信息，我们需要从顶往下找。最近的 DNS 服务器中保存了根域DNS服务器的信息，因此它会将来自客户端的查询消息转发给根域DNS服务器，根域服务器中也没有www.lab.glasscom.com这个域名，但根据域名结构可以判断这个域名属于com域，因此根域 DNS 服务器会返回它所管理的com域中的DNS服务器的IP地址。接下来最近的DNS服务器又会向com域的DNS服务器发送查询消息com域中也没有www.lab.glasscom.com这个域名的信息，和刚才一样com域服务器会返回它下面的 glasscom.com域的DNS服务器的IP地址。以此类推，只要重复前面的步骤，就可以顺藤摸瓜找到目标DNS服务器。整个过程如下图所示。

<img src="/img/post/network-dns.png" width="600"/>

对于客户端来说，其实还有一部就是本地dns缓存，本地dns缓存也就是在/etc/hosts文件，这也是为啥我们可以在hosts文件中重定向域名对应的ip地址。

传统的DNS存在哪些问题：
> 1. 域名缓存问题
> 2. 域名转发问题
> 3. 出口NAT问题
> 4. 域名更新问题
> 5. 解析延迟问题

为了解决这5个问题，腾讯最初提出了HTTPDNS，HTTPDNS工作原理如下图所示：
<img src="/img/post/network-httpdns.png" width="600"/>

其主要思想就是给自己服务器自建dns，自己能控制dns解析到具体哪个服务器的ip，自定义缓存失效策略，负责均衡策略等。HTTPDNS具体实现机制可以阅读下这篇文章 [腾讯千亿级HttpDNS服务是怎样炼成的](https://mp.weixin.qq.com/s?__biz=MzA3ODgyNzcwMw==&mid=2649021597&idx=1&sn=ec34bedde480e5d564ff88c46ffb148b&chksm=87aca545b0db2c535a09fad570537e608e61cc2bcb0394ae98d3a56e4ec99a2c8cfbf491ba17&scene=0&ascene=7&devicetype=android-24&version=2607023a&nettype=WI)

#### 1.3 套接字Socket

在建立Socket时候，往往意识不到中间经历过多少局域网，多少路由器。在网络层，Socket需要指定到底是ipv4还是ipv6。下面以TCP为例说下整个Socket套接字过程。
TCP的服务器需要先监听一个端口，一般是先调用bind函数给socket ip地址和端口号。为什么要端口号了？应用程序当一个网络包来的时候，内核要通过TCP头里面的这个端口来找到应用程序，然后把包丢给应用程序。那么为什么又需要IP地址了，有时候一台机器有多个网卡，也就对应多个IP地址，可以选择监听不同的网卡，这样只有发给发送这个网卡的包才会转发给你。

在内核中会为每个socket维护两个队列，一个是已经建立连接的队列，这个队列的三次握手都已经经过了，处于established状态；还有一个是没有完全建立连接的队列，这个队列三次握手还没有完成，处于syn_rcvd状态。
客户端调用connect函数发起连接后，开始三次握手，内核会给客户端分配一个临时端口，一旦握手成功，服务器accept就返回另外一个socket。也即是监听的socket和真正用来传输数据的socket是两个，一个是监听socket另外一个叫已连接socket。

服务器端最大连接数理论上限 = 客户端ip数 * 客户端端口数 = 2的32次方 * 2的16次方，但是这是理论上限，由于操作系统文件描述符限制，socket都是文件，虽然我们可以修改这个文件描述符数目，但是文件描述符都是占用内存的，所以服务器的最大并发远达不到这个数量级。

为了解决Socket套接字限制，出来了三种IO模型(BIO, NIO, AIO)，可以看看这篇文章简单解释。
[https://www.jianshu.com/p/d23f6d261a04](https://www.jianshu.com/p/d23f6d261a04)

socket连接后，需要经历三次握手，那三次握手具体是怎么操作的了，请看下图动画所示：

<img src="/img/post/network-http-handshake.gif" width="600"/>

这里有一个问题，为什么tcp是三次握手，而不是2次，或者4次5次6次了？
如果是两次握手，那么必然是不需要最后一次，这会导致server端发给客户端的包server不知道有没有收到，也就不能确定这个连接是不是有效的。对于大于3次握手也是可以的，但是这真的没有必要。

TCP发送数据完需要关闭socket通道，就需要经历四次挥手，如下图所示：

<img src="/img/post/network-http-close.gif" width="600"/>

从上图看断开连接过程比建立连接过程复杂多了，为啥了？这就好像编程时候申请内存容易但是释放内存难。

这里涉及到的概念比较多，可以参考 [https://www.jianshu.com/p/44655bff60a4](https://www.jianshu.com/p/44655bff60a4)
这里其中有两个很重要的概念对于定位问题非常重要，第一是Time_Close,第二个是Time_Wait,可以通过下面两个命令查看系统资源试用情况

```shell
➜  ~ netstat -a | grep -i CLOSE_WAIT | wc -l
➜  ~ netstat -a | grep -i TIME_WAIT | wc -l
```

如果系统的close_wait 过多，很大可能说明应用程序有问题。

应用程序在调用write发送数据时候并不指定发送数据的长度，在操作系统协议栈看来这就是二进制数据而已，操作系统协议栈并不是收到数据马上发送出去，它会先数据放到一个缓冲区，如果每次应用程序收到数据包就将数据马上发送出去，这可能导致大量小包，导致网络拥堵。判断是不是要将缓冲区的数据发送出去，一般依赖MTU和时间两个要素来控制，MTU是一个网路包的最大长度，以太网一般是1500（包含协议头），MTU和时间都是由操作系统控制。

### 2. 网络传输要做的事情
本节探索网络包进入互联网之前和在互联网传输过程中经历的过程，网络包从客户端计算机出发经过集线器，交换机和路由器，最终进入互联网，实际上家用路由器包含了集线器和交换机功能。

计算机程序处理包括存储的都是二进制数据，二进制数据是怎么到达远在天边的服务器的了？要彻底弄清楚这个之前，我们要先知道以下三类协议有啥区别，都是干啥的。
> 1. TCP/UDP协议
> 2. IP协议
> 3. 以太网协议

TCP/UDP协议：可以理解为是受咋们程序控制的，他的作用就是用来将数据包裹起来传递给对方，类似快递打包过程。
IP协议：要将快递从A送到B，中间肯定经历不同的站点，IP作用就是用来寻找下一个站点用的。
以太网协议：这个就是用来真正传输数据的数据链路，可以用飞机送，可以用绿皮车等。

#### 2.1 快递打包


#### 2.2 寻找站点

<img src="/img/post/network-ip-router.png" width="600"/>

上图很形象描述了IP网络包传输方式，其实就是每经过一个路由器，这个路由器负责填写下一个路由器ip地址和mac地址。
这里还有一个疑问，它是怎么知道下一跳的ip和mac地址的了(注意这里只会修改包的mac，源ip和目标ip在整个路由过程中都不会变化)。

下一跳的ip地址是通过路由表查到的，下一跳ip的mac地址是通过ARP地址解析协议拿到的。这里衍生出另外两个问题：
> 1. 路由器加入到网络后，路由表怎么维护的？
> 2. ARP 获取mac地址是广播给谁，拿不到ip对应的mac地址咋办？

问题一：有两类算法，第一种是距离矢量路由算法，这个算法很笨，就是每个路由器知道所有其他路由器的距离。他每隔几秒把自己知道的告诉邻居，然后获取从邻居相应的信息。另外一个是链路状态路由算法，这个算法基本思想是，当一个路由器启动时候，首先向邻居发送hello信息，所有邻居都回复，然后计算和邻居的距离，接下来将自己和邻居的链路状态广播出去，发送到整个网络的每个路由器中，这样每个路由器都能够收到它和邻居之间的关系信息，这样每个路由器都能构建一个完整的网络拓扑图。

这两个算法都有自己的应用场景，基于链路状态路由算法的OSPF路由协议，和基于距离矢量路由算法的BGP(Border Gateway Protocol)路由协议，OSPF广泛应用于数据中心。上面的两个算法都是基于所有路由器连接在一起，但是在真实网络中，这是不可能的。为了解决全世界的网络都连在一起这个问题，人们将网络按区块分、层级分，同一区域内的数据包在区域内路由，不再同一区域的包才发往其他区域。区域之间的路由通过边界路由器，这样就是网络里面的自治系统，BGP协议负责将全世界的自治系统连接起来。

下图描述了一个自治系统里面的数据包流转流程。
<img src="/img/post/network-transfer_within-an-as.jpg" width="600"/>
上图R1-R6都是路由器，每个路由器都有4个接口，每个接口都绑定一个ip地址。这里假设Sender发一个包往Receiver

> 1. Sender要发送数据包给Receiver，通过路由表查询到，其下一跳路由器地址是R1上的1接口绑定的IP（后面表示为R1-1-ip）。Sender通过ARP协议获得了R1-1-ip处的MAC地址，通过查询转发表，得到数据包要去往R1-1-ip，需要通过其与R1的唯一个接口传输出去。
> 2. R1-1接收到数据包时，通过查询路由表，查到数据包要发送往Receiver需要经过R4-1-ip，即其下一跳地址是R4-1-ip，R1通过ARP协议得到R4-1的Mac地址，然后通过转发表查询到数据包要从R1发往R4，需要通过R1-4这个接口，于是数据包通过R1-4这个接口连接的链路，发送到了R4。
> 3. R4收到数据包以后，由于Receiver所在的网络与自己的R4-4接口连接，于是数据包通过R4-4最终传输到Receiver中。 

自治系统通俗点说就是网络世界的一个王国，中国电信和中国移动，中国电信通过BGP学习到中国移动的路由信息，就会把用户访问中国移动服务器的请求转发给中国移动的边界路由器。

问题二：可以参考这个分享 [https://zhuanlan.zhihu.com/p/28771785](https://zhuanlan.zhihu.com/p/28771785)。

数据包路由过程中有三个很重要的概念
> 1. TTL(timve to live)，TTL是经过路由器的跳数，没经过一个路由器，TTL都要减1，如果TTL为0还没有达到目的地，数据包就被扔掉。
> 2. MTU，它表示一个网络包的最大长度，以太网一般是1500字节，数据报经过不同的路由器会有不同的MTU。
> 3. RTT，一个数据包从发送到收到回执的往返时间。

网络世界有一个很重要的ICMP互联网控制报文协议（Internet Control Message Protocol），我们经常用的ping和traceroute都是基于它实现的。

#### 2.3 链路数据传输

宽带上网数据链路传输分为两类
> 1. 电话线/光纤通信
> 2. 无线通信（wifi/2G/3G/4G/5G）

宽带上网最早是拨号上网，拨号上网用的是电话线网络数据传输，而且一旦你拨号上网就不能打电话了，而且费用贵速度慢。后台开始有了ADSL上网，ADSL也是基于电话线上网，只是充分发挥了电话线的作用，将速度提高到20Mbps，不过再怎么发挥电话线作用，铜线毕竟是铜线，速度还是有天然限制的。于是就有了后面的光纤通讯。光纤通讯原理可以看这个[视频](https://www.ixigua.com/i6607346214662832647/#mid=4234740937)

那通常我们小区里面光纤入户到底是啥概念了，下图描述了接入互联网主干网络的主要部分。
<img src="/img/post/network-p.png" width="600"/>

对于无线4g上网流程如下图所示。
<img src="/img/post/network-4g.png" width="600"/>

手机通过4G上网第一是查找信号，这首先会搜索附近的信号塔eNodeB，连接到eNodeB后，eNodeB请求MME要认证手机，接下来就是手机鉴权阶段（手机是不是工信部认证了，手机啥套餐，是不是欠费了）。如果认证通过了就告诉SGW创建一个回话，SGW向PGW建立一个回话，PGW是出口网关，出口网关里面有一个计费单元，他就是用来计算我们每个月流量费用的😄。<commit_msg>update post<commit_after>---
layout:     post		
title:      "网络是怎样连接的"		
date:       2018-10-14	
author:     "KingXt"		
tags:
    - 网络
---

# 网络是怎样连接的

淘宝手机客户端浏览商品是怎么获取到服务器数据的？这里会衍生出以下一些问题。

<img src="/img/post/network-question.png" width="600"/>

上图一些列问题反映了很多知识点，接下来会一个一个通俗点描述其工作原理。

### 从下面三个方面可以更加有一个直观认识
> 1. 客户端要做的事情
> 2. 网络传输要做的事情
> 3. 服务器要做的事情


### 1. 客户端要做的事情

不管是手机客户端还是pc，客户端发送内容到服务器都需要经过下面几个过程:
> 1. 生成http请求消息
> 2. 向dns服务器查询服务器的ip地址
> 3. 委托协议栈发送消息，创建套接字Socket，发送数据，断开服务器连接

#### 1.1 生成http请求消息
Http请求消息是应用程序生成的，而且有一些第三方库很方便应用开发者生成请求消息内容，比如android应用程序可以用okhttp，ios应用程序可以用NSURLSession，go提供的net库等。但是http请求消息体都有其标准格式，如下图所示：

<img src="/img/post/network-request.png" width="600"/>

http请求消息生成之后，由于应用本身不具备将消息发送到网络功能，这需要将这个任务交给操作系统来实现，但是交给操作系统之前，比如要将域名解析为对应的IP地址。如果本来就是通过IP直接访问，那么这个步骤就省略了。

#### 1.2 向dns服务器查询服务器的ip地址

这里先介绍下IP地址是什么？ 如下图所示：

<img src="/img/post/network-ip.png" width="600"/>

主机号部分的比特全部为0或者全部为1时代表以下两种特殊的含义。
> 1. 主机号部分全部为0代表整个子网而不是子网中的某台设备。
> 2. 主机号部分全部为1代表向子网上所有设备发送包，即广播.

域名解析过程入下图www.lab.glasscom.com所示，肯定会先访问最近的一台DNS服务器，如果最近的DNS服务器没有存放域名对应信息。由于最近的DNS服务器没有存放www.lab.glasscom.com对应的信息，我们需要从顶往下找。最近的 DNS 服务器中保存了根域DNS服务器的信息，因此它会将来自客户端的查询消息转发给根域DNS服务器，根域服务器中也没有www.lab.glasscom.com这个域名，但根据域名结构可以判断这个域名属于com域，因此根域 DNS 服务器会返回它所管理的com域中的DNS服务器的IP地址。接下来最近的DNS服务器又会向com域的DNS服务器发送查询消息com域中也没有www.lab.glasscom.com这个域名的信息，和刚才一样com域服务器会返回它下面的 glasscom.com域的DNS服务器的IP地址。以此类推，只要重复前面的步骤，就可以顺藤摸瓜找到目标DNS服务器。整个过程如下图所示。

<img src="/img/post/network-dns.png" width="600"/>

对于客户端来说，其实还有一部就是本地dns缓存，本地dns缓存也就是在/etc/hosts文件，这也是为啥我们可以在hosts文件中重定向域名对应的ip地址。

传统的DNS存在哪些问题：
> 1. 域名缓存问题
> 2. 域名转发问题
> 3. 出口NAT问题
> 4. 域名更新问题
> 5. 解析延迟问题

为了解决这5个问题，腾讯最初提出了HTTPDNS，HTTPDNS工作原理如下图所示：
<img src="/img/post/network-httpdns.png" width="600"/>

其主要思想就是给自己服务器自建dns，自己能控制dns解析到具体哪个服务器的ip，自定义缓存失效策略，负责均衡策略等。HTTPDNS具体实现机制可以阅读下这篇文章 [腾讯千亿级HttpDNS服务是怎样炼成的](https://mp.weixin.qq.com/s?__biz=MzA3ODgyNzcwMw==&mid=2649021597&idx=1&sn=ec34bedde480e5d564ff88c46ffb148b&chksm=87aca545b0db2c535a09fad570537e608e61cc2bcb0394ae98d3a56e4ec99a2c8cfbf491ba17&scene=0&ascene=7&devicetype=android-24&version=2607023a&nettype=WI)

#### 1.3 套接字Socket

在建立Socket时候，往往意识不到中间经历过多少局域网，多少路由器。在网络层，Socket需要指定到底是ipv4还是ipv6。下面以TCP为例说下整个Socket套接字过程。
TCP的服务器需要先监听一个端口，一般是先调用bind函数给socket ip地址和端口号。为什么要端口号了？应用程序当一个网络包来的时候，内核要通过TCP头里面的这个端口来找到应用程序，然后把包丢给应用程序。那么为什么又需要IP地址了，有时候一台机器有多个网卡，也就对应多个IP地址，可以选择监听不同的网卡，这样只有发给发送这个网卡的包才会转发给你。

在内核中会为每个socket维护两个队列，一个是已经建立连接的队列，这个队列的三次握手都已经经过了，处于established状态；还有一个是没有完全建立连接的队列，这个队列三次握手还没有完成，处于syn_rcvd状态。
客户端调用connect函数发起连接后，开始三次握手，内核会给客户端分配一个临时端口，一旦握手成功，服务器accept就返回另外一个socket。也即是监听的socket和真正用来传输数据的socket是两个，一个是监听socket另外一个叫已连接socket。

服务器端最大连接数理论上限 = 客户端ip数 * 客户端端口数 = 2的32次方 * 2的16次方，但是这是理论上限，由于操作系统文件描述符限制，socket都是文件，虽然我们可以修改这个文件描述符数目，但是文件描述符都是占用内存的，所以服务器的最大并发远达不到这个数量级。

为了解决Socket套接字限制，出来了三种IO模型(BIO, NIO, AIO)，可以看看这篇文章简单解释。
[https://www.jianshu.com/p/d23f6d261a04](https://www.jianshu.com/p/d23f6d261a04)

socket连接后，需要经历三次握手，那三次握手具体是怎么操作的了，请看下图动画所示：

<img src="/img/post/network-http-handshake.gif" width="600"/>

这里有一个问题，为什么tcp是三次握手，而不是2次，或者4次5次6次了？
如果是两次握手，那么必然是不需要最后一次，这会导致server端发给客户端的包server不知道有没有收到，也就不能确定这个连接是不是有效的。对于大于3次握手也是可以的，但是这真的没有必要。

TCP发送数据完需要关闭socket通道，就需要经历四次挥手，如下图所示：

<img src="/img/post/network-http-close.gif" width="600"/>

从上图看断开连接过程比建立连接过程复杂多了，为啥了？这就好像编程时候申请内存容易但是释放内存难。

这里涉及到的概念比较多，可以参考 [https://www.jianshu.com/p/44655bff60a4](https://www.jianshu.com/p/44655bff60a4)
这里其中有两个很重要的概念对于定位问题非常重要，第一是Time_Close,第二个是Time_Wait,可以通过下面两个命令查看系统资源试用情况

```shell
➜  ~ netstat -a | grep -i CLOSE_WAIT | wc -l
➜  ~ netstat -a | grep -i TIME_WAIT | wc -l
```

如果系统的close_wait 过多，很大可能说明应用程序有问题。

应用程序在调用write发送数据时候并不指定发送数据的长度，在操作系统协议栈看来这就是二进制数据而已，操作系统协议栈并不是收到数据马上发送出去，它会先数据放到一个缓冲区，如果每次应用程序收到数据包就将数据马上发送出去，这可能导致大量小包，导致网络拥堵。判断是不是要将缓冲区的数据发送出去，一般依赖MTU和时间两个要素来控制，MTU是一个网路包的最大长度，以太网一般是1500（包含协议头），MTU和时间都是由操作系统控制。

### 2. 网络传输要做的事情
本节探索网络包进入互联网之前和在互联网传输过程中经历的过程，网络包从客户端计算机出发经过集线器，交换机和路由器，最终进入互联网，实际上家用路由器包含了集线器和交换机功能。

计算机程序处理包括存储的都是二进制数据，二进制数据是怎么到达远在天边的服务器的了？要彻底弄清楚这个之前，我们要先知道以下三类协议有啥区别，都是干啥的。
> 1. TCP/UDP协议
> 2. IP协议
> 3. 以太网协议

TCP/UDP协议：可以理解为是受咋们程序控制的，他的作用就是用来将数据包裹起来传递给对方，类似快递打包过程。
IP协议：要将快递从A送到B，中间肯定经历不同的站点，IP作用就是用来寻找下一个站点用的。
以太网协议：这个就是用来真正传输数据的数据链路，可以用飞机送，可以用绿皮车等。

#### 2.1 快递打包


#### 2.2 寻找站点

<img src="/img/post/network-ip-router.png" width="600"/>

上图很形象描述了IP网络包传输方式，其实就是每经过一个路由器，这个路由器负责填写下一个路由器ip地址和mac地址。
这里还有一个疑问，它是怎么知道下一跳的ip和mac地址的了(注意这里只会修改包的mac，源ip和目标ip在整个路由过程中都不会变化)。

下一跳的ip地址是通过路由表查到的，下一跳ip的mac地址是通过ARP地址解析协议拿到的。这里衍生出另外两个问题：
> 1. 路由器加入到网络后，路由表怎么维护的？
> 2. ARP 获取mac地址是广播给谁，拿不到ip对应的mac地址咋办？

问题一：有两类算法，第一种是距离矢量路由算法，这个算法很笨，就是每个路由器知道所有其他路由器的距离。他每隔几秒把自己知道的告诉邻居，然后获取从邻居相应的信息。另外一个是链路状态路由算法，这个算法基本思想是，当一个路由器启动时候，首先向邻居发送hello信息，所有邻居都回复，然后计算和邻居的距离，接下来将自己和邻居的链路状态广播出去，发送到整个网络的每个路由器中，这样每个路由器都能够收到它和邻居之间的关系信息，这样每个路由器都能构建一个完整的网络拓扑图。

这两个算法都有自己的应用场景，基于链路状态路由算法的OSPF路由协议，和基于距离矢量路由算法的BGP(Border Gateway Protocol)路由协议，OSPF广泛应用于数据中心。上面的两个算法都是基于所有路由器连接在一起，但是在真实网络中，这是不可能的。为了解决全世界的网络都连在一起这个问题，人们将网络按区块分、层级分，同一区域内的数据包在区域内路由，不再同一区域的包才发往其他区域。区域之间的路由通过边界路由器，这样就是网络里面的自治系统，BGP协议负责将全世界的自治系统连接起来。

下图描述了一个自治系统里面的数据包流转流程。
<img src="/img/post/network-transfer_within-an-as.jpg" width="600"/>
上图R1-R6都是路由器，每个路由器都有4个接口，每个接口都绑定一个ip地址。这里假设Sender发一个包往Receiver

> 1. Sender要发送数据包给Receiver，通过路由表查询到，其下一跳路由器地址是R1上的1接口绑定的IP（后面表示为R1-1-ip）。Sender通过ARP协议获得了R1-1-ip处的MAC地址，通过查询转发表，得到数据包要去往R1-1-ip，需要通过其与R1的唯一个接口传输出去。
> 2. R1-1接收到数据包时，通过查询路由表，查到数据包要发送往Receiver需要经过R4-1-ip，即其下一跳地址是R4-1-ip，R1通过ARP协议得到R4-1的Mac地址，然后通过转发表查询到数据包要从R1发往R4，需要通过R1-4这个接口，于是数据包通过R1-4这个接口连接的链路，发送到了R4。
> 3. R4收到数据包以后，由于Receiver所在的网络与自己的R4-4接口连接，于是数据包通过R4-4最终传输到Receiver中。 

自治系统通俗点说就是网络世界的一个王国，中国电信和中国移动，中国电信通过BGP学习到中国移动的路由信息，就会把用户访问中国移动服务器的请求转发给中国移动的边界路由器。

问题二：可以参考这个分享 [https://zhuanlan.zhihu.com/p/28771785](https://zhuanlan.zhihu.com/p/28771785)。

数据包路由过程中有三个很重要的概念
> 1. TTL(timve to live)，TTL是经过路由器的跳数，没经过一个路由器，TTL都要减1，如果TTL为0还没有达到目的地，数据包就被扔掉。
> 2. MTU，它表示一个网络包的最大长度，以太网一般是1500字节，数据报经过不同的路由器会有不同的MTU。
> 3. RTT，一个数据包从发送到收到回执的往返时间。

网络世界有一个很重要的ICMP互联网控制报文协议（Internet Control Message Protocol），我们经常用的ping和traceroute都是基于它实现的。Ping原理是构建一个ICMP报文，源主机如果收到ICMP应答包，则可以计算数据包时延。如果收不到则说明目标主机不可达。我们不能认为Ping不通代表网络不通， 衣蛾有些中间设备禁止Ping，这个时候telnet就派上用场了。
Traceroute可以追踪到达目的地经过的路由器。traceroute是通过修改发出去的UDP数据包的TTL值来实现的，比如修改成1，到达第一个路由器并受到ICMP报文回应就知道第一个路由器地址。但是有些路由器就是傲慢，它错了也不返回回应。traceroute还可以设置数据包不分片传输来确定路径MTU大小，原理是发送数据包时候故意设置不分片，当收到ICMP差错报文时候就知道发出去的数据包太大了，我们可以逐步缩小数据包大小来确定路径MTU大小。

#### 2.3 链路数据传输

宽带上网数据链路传输分为两类
> 1. 电话线/光纤通信
> 2. 无线通信（wifi/2G/3G/4G/5G）

宽带上网最早是拨号上网，拨号上网用的是电话线网络数据传输，而且一旦你拨号上网就不能打电话了，而且费用贵速度慢。后台开始有了ADSL上网，ADSL也是基于电话线上网，只是充分发挥了电话线的作用，将速度提高到20Mbps，不过再怎么发挥电话线作用，铜线毕竟是铜线，速度还是有天然限制的。于是就有了后面的光纤通讯。光纤通讯原理可以看这个[视频](https://www.ixigua.com/i6607346214662832647/#mid=4234740937)

那通常我们小区里面光纤入户到底是啥概念了，下图描述了接入互联网主干网络的主要部分。
<img src="/img/post/network-p.png" width="600"/>

对于无线4g上网流程如下图所示。
<img src="/img/post/network-4g.png" width="600"/>

手机通过4G上网第一是查找信号，这首先会搜索附近的信号塔eNodeB，连接到eNodeB后，eNodeB请求MME要认证手机，接下来就是手机鉴权阶段（手机是不是工信部认证了，手机啥套餐，是不是欠费了）。如果认证通过了就告诉SGW创建一个回话，SGW向PGW建立一个回话，PGW是出口网关，出口网关里面有一个计费单元，他就是用来计算我们每个月流量费用的😄。
{'fraction_non_alphanumeric': 0.10890506654901096, 'fraction_numerical': 0.045665122435473195, 'mean_word_length': 11.23021582733813, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 77, 'https://': 16, 'lorem ipsum': 0, 'www.': 18, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '815576', 'n_tokens_mistral': 11252, 'n_tokens_neox': 12709, 'n_words': 412}