小林计网基础篇

TCP / IP 网络模型有哪几层?

同一台设备上的进程间的通信方式有很多种, 管道、消息队列、共享内存、信号等.

不同设备上的进程间的通信方式就需要 网络通信, 而设备是多样的, 所以为了兼容就提出了一套通用的网络协议

协议是分层的, 每一层职责不同, 接下来根据「TCP / IP 网络模型」分别对每一层介绍.

应用层 Application Layer

我们直接接触到的就是应用层.

手机或者电脑使用的应用软件也都是在应用层实现.

应用层只需要为用户提供应用功能, 如 HTTP、FTP、Telnet、DNS、SMTP 等

应用层只是工作在操作系统里的用户态, 传输层以下则工作在内核态

应用层将两个设备之间需要通信的数据传输给传输层, 让传输层实现之后的功能

传输层 Transport Layer

image-20220604162424337

设备作为发送方

涉及到传输层的两个协议 TCP 和 UDP

  • TCP 传输控制协议(Transmission Control Protocol), 正如它名字所说, TCP 协议是会对数据进行控制的, 所以数据的传输会比较稳定 大部分应用使用都是 TCP , 比如 HTTP 应用层协议. TCP 与 UDP 相比多了很多特性, 如 流量控制、超时重传、拥塞(se)控制 等等
  • UDP 用户数据报协议(User Datagram Protocol), 不保证数据包是否能抵达对方, 过因此传输的实时性和传输效率会更高
  • 如果需要传输的数据非常大, 直接传输可能就会不好控制损失. 因此当传输层的数据包大小超过 MSS (TCP最大报文段长度), 就会将数据包分块(TCP段), 这样即使传输途中有一个分块损坏或者丢失了, 只需要重新发送这个段( TCP segment)就行. image-20220604164046762

设备作为接收方

传输层需要把数据包传给应用, 但是同一台设备上会有很多应用, 因此我们常常会使用端口将应用区分开来.

80 端口通常是 Web 服务器使用, 22 端口通常是远程登录服务器. 浏览器中每一个标签栏都是一个独立的进程, 操作系统会临时为这些进程分配临时端口号.

传输层报文会携带端口号, 因此接收方可以识别出该报文是发送给哪个应用

传输层是应用间的数据传输的媒介, 帮助实现应用到应用的通信

网络层 Internet Layer

负责实际的数据传输功能

网络层最常用的就是 IP 协议 (Internet Protocol)

IP 协议会将 IP 包 + 传输层的报文 组装成 IP 报文, 如果报文大小超过 MTU(以太网中一般为 1500 字节), 就会再次进行分片

image-20220604204647699

IP 地址的划分

网络层通过使用 IP 地址 给设备进行编号来在网络中找到对应的设备, 对于 IPv4 协议, IP 地址共 32 位, 分成四段(如 192.168.0.1)

同时为了减少直接遍历 所有 IP 地址 来查找对应设备的低效, 我们将 IP 地址分为两种含义

  • 网络号, 标识该 IP 地址 是属于哪个子网
  • 主机号, 标识同一子网下的不同主机

通过子网掩码, 来算出 IP 地址的网络号和主机号 (比如10.100.122.0/24就是带子网掩码的 IP 地址), 具体计算如下图

image-20220604205811177

IP 协议的寻址和路由

寻址: 通过子网掩码算出网络号和主机号, 匹配到相应的网络号, 也就是找到同一个子网, 然后再去找对应的主机

路由: 当数据包遇到网络节点(网关、路由器、交换机等)后, 通过路由算法, 决定下一条走哪条路径

image-20220604210759840

所以, IP 协议的 寻址是「告诉我们目的地」, 路由则是「选择去往下一节点的路径」

负责在网络中寻找目标设备, 将数据从一个网络中送到另一个网络

网络接口层 Link Layer (数据链路层)

在 IP 的头部前面加上 MAC 头部, 封装成 数据帧(Data Frame) 发送到网络上.

  • 以太网 电脑上的 以太网接口、Wi-Fi 接口、以太网交换机、路由器上的千兆、万兆以太网口、网线, 他们都是组成以太网的一部分. 就是在局域网内, 将附近设备都连接起来通讯的技术 以太网中, 设备间的通讯就是使用 MAC 地址.

MAC 头部是以太网使用的头部, 包含了接收方和发送方的 MAC 地址等信息, 我们可以通过 ARP 协议获取对方的 MAC 地址

网络接口层(数据链路层) 是工作在网卡层次, 使用 MAC 地址标识网络上的设备, 有点类似于每个物品的物理地址

总结

TCP / IP 网络通常是自上到下分成 4 层, 如下图

image-20220604213851397

每一层封装的数据格式

应用层HTTP 协议传输单位是 消息或报文(message)

传输层TCP 协议传输单位是 段(segment)

网络层IP 协议传输单位是 包(packet)

网络接口层的传输单位是 帧(frame)

这些名词没有什么本质的区分, 可以统称为数据包.

image-20220604214129271

从键入网址到网页显示, 期间发生了什么?

总流程大致如下图

image-20220613193759342

弱小数据包 — HTTP

  1. 解析 URL , 生成发送给 Web 服务器的请求信息
image-20220613202413731

如果省略了蓝色部分的文件路径, 则访问根目录下实现设定好的默认文件, 如 index.html

  1. 生产 HTTP 请求信息

URL解析之后, 浏览器确定了 Web 服务器和文件名, 接下来就是根据这些信息生成 HTTP 请求消息了.

image-20220613202739722

自此, 数据包就准备完毕了, 上路前往目的地

查询真实地址 — DNS

这时, HTTP 消息就可以委托操作系统来发送消息了, 不过发送之前, 我们必须得知道目的地的 IP , 所以需要查询服务器域名对应的 IP 地址

DNS 服务器 就保存了 域名 和 对应 IP 的关系

域名层级关系, 越靠右边层级越高

image-20220613203936593

域名解析的过程类似于生活中的 只指路不带路

域名解析过一次之后就会将对应信息存入缓存

查找顺序是; 浏览器 > 操作系统 > hosts > 本地 DNS 服务器

到达这一步之后, 总算是知道目的地的具体地址了, 现在就是需要寻找前往目的地的方法了

地图指南 — 协议栈

获取到 IP 之后, HTTP 就会去寻求 操作系统中的协议栈 ‘地图’的帮助

image-20220613204425532

应用程序(浏览器)通过调用 Socket 库, 来委托协议栈工作

协议栈分为上半和下半

  • 上半: 收数据和发数据的 TCP 和 UDP 协议,
  • 下半: IP 协议控制网络包收发操作, IP 中还包括 ICMPARP 协议
  • ICMP 用于告知各种传输时的错误信息
  • ARP 用于 IP 查询以太网 MAC 地址

网卡驱动程序控制网卡完成收发操作

看完这份地图之后, 数据包就知道要先去找 TCP

保证可靠的传输 — TCP

HTTP 是基于 TCP 协议传输的

image-20220613205759167

源端口号目标端口号是必不可少的, 不然就不知道要发给那个应用

序号可以解决包乱序问题

确认号会确认对方是否有收到, 没有收到就应该重新发送

状态位 代表发送时状态的变化. 如 SYN 是发起连接, ACK 是回复, RST 是重新连接, FIN结束连接

窗口大小 供 TCP 做流量控制, 通信双方声明一个窗口, 标识自己的处理能力

TCP 传输前建立的三次握手

image-20220613212717523
  1. 双方都处于CLOSE状态
  2. 服务端开始监听客户端的请求, 进入LISTEN状态
  3. 客户端发出请求SYN, 进入SYN_SENT 状态
  4. 服务端收到请求, 返回SYN, 并且ACK回复客户端的 SYN, 进入SYN_RCVD 状态
  5. 客户端收到服务端返回的SYNACK, 发送对服务端确认的ACK, 进入ESTABLISHED状态, 因为一发一收成功了
  6. 服务端收到ACKACK后, 进入ESTABLISHED状态

三次握手保证了双方都有发送和接收的能力

在 Linux 的可以通过 netstat -napt 查看 TCP 的连接状态

image-20220613213514436

TCP 分割数据

如果 HTTP 消息超过 MSS 的长度, TCP 将会对数据进行分段.

image-20220613213633186

TCP 报文生成

image-20220613213806112

此时, 数据包已经被 TCP 头部给保护了, 保证了可靠的送达, 接下来就是找 IP 模块来对数据进行进一步的封装了

远程定位 — IP

IP 协议里有 源地址 IP目标地址 IP

  • 源地址 IP : 客户端 IP
  • 目标地址 IP : DNS 解析出来的 IP

IP 包头的协议号, 要写为 06 , 表示协议为 TCP

客户端有多个网卡, IP 源地址应该选择哪一个?

通过判断是哪一张网卡发送的请求, 就可以知道是哪一张网卡发送包.

需要通过路由表, 来判断

Linux 中, 可以通过 route -n 查看当前的路由表

image-20220613214635830

计算规则是

将 目标 IP 与 Genmask 子网掩码进行 & 运算, 得到的结果如果与对应目标 IP 的 Destination 一致, 则使用这张网卡进行发送

如果发现与其他所有条目都不匹配, 则会与 0.0.0.0 默认网关 进行匹配, , 并将包发送给路由器, 即 Gateway , 也就是路由器的 IP 地址

IP 报文生成

image-20220613215317556

此时已经有了 TCP 和 IP 的保证可靠和指路, 那么接下来就需要 MAC 来进行物理地址的引导了

两点传输 — MAC

包括 接收方 MAC 地址发送方 MAC 地址

还有协议类型, 一般为 0800 : IP 协议, 0806: ARP 协议

MAC 接收方和发送方如何确定?

发送方: 从网卡的 ROM 中直接读取即可

接收方: 需要通过 路由表 查询到的 IP , 通过 ARP 协议 帮助我们找到 对应 IP 的 MAC 地址

image-20220613220138392

ARP 协议会以 广播 的形式, 对以太网中所有设备询问目标 IP 的 MAC 地址

以太网是一种局域网

ARP 广播获取之后的 MAC 地址将会进入 ARP 缓存, 但缓存时间就几分钟

Linux 中, arp -a查看 ARP 缓存

image-20220613220558104

MAC 报文生成

image-20220613220616318

此时, 终于完成了所有地址的查询, 可以准备上路了

出口 — 网卡

数字信号转换为电信号

通过网卡实现, 网卡驱动程序控制网卡

网卡驱动获取网络包之后, 将会存入网卡缓冲区中, 并在开头加上报头和起始帧分界符, 末尾加上检测错误的帧效验序列

image-20220613220948677

数据包成功转化为电信号, 发送出去

送别者 — 交换机

交换机工作在 MAC 层, 成为 二级网络设备

交换机将电信号转换为数字信号

通过 FCS 效验错误, 没问题放入缓冲区

网卡会核对 MAC 地址判断是否是发给自己的, 如果不是, 则丢弃; 而交换机端口全部接收放入缓冲区, 交换机端口无 MAC 地址

包存入缓冲区之后, 查询 MAC 地址表, 将包发送到对应的端口去

image-20220613221711294

交换机根据 MAC 地址表查找 MAC 地址, 然后将信号发送到相应的端口.

MAC 地址表 找不到指定 MAC 地址怎么办?

交换机会将包转发到除了源端口之外的所有端口

因为只有相应的接收者才会接收这个包, 其他设备会直接忽略这个包

如果 MAC 地址 是一个 广播地址 , 那么交换机也会将包发送到除源端口之外的所有端口

# 广播地址
MAC  FF:FF:FF:FF:FF:FF
IP   255.255.255.255

此时数据包终于可以出门了, 交换机成功将它转发到了对应的端口

中转巴士 — 路由器

路由器其实就是一台小型计算机

路由器: 基于 IP 设计的, 是三层网络设备, 各个端口都有 MAC 和 IP 地址

交换机: 基于 以太网 设计的, 是二层网络设备, 不具有 MAC 地址

工作原理

路由器端口有 MAC 地址, 能成为以太网的接收方和发送方; 同时还具有 IP 地址, 与网卡类似.

转发包时, 路由器会先接收发送给自己的以太网包, 然后在路由表查询下一个要发送的目标, 再由相应的端口将以太网包发送出去

包接收操作

电信号到达网线接口, 路由器将电信号转换为数字信号, 然后通过 FCS 进行错误效验

如果没问题就检查包 MAC 头部中接收方 MAC 地址, 看看是不是发送自己的包, 是的话就放入缓冲区, 否则丢弃, 类似网卡

查询路由表确定输出端口

完成包接收操作后, 路由器就会去掉包开头的 MAC 地址.

MAC 地址的作用就是将包送达路由器, 不过在前往新的路由器时, 还会再次查询下一个地点的 MAC 地址

接下来, 路由器会根据 IP 地址 进行包的转发操作, 计算规则类似于 IP 源地址选择目标地址

image-20220614111347015

路由器的发送操作

  • 根据网关判断是否抵达终点
  • 如果网关是一个 IP 地址, 那么这就是我们要前往的下一个 路由器 地址, 还未抵达终点
  • 如果网关为空, 则 IP 头部的接收方 IP 地址就是要转发到的 目标地址, 说明 已抵达终点
  • 接下来通过 ARP协议根据 IP 地址查询 MAC 地址, 将查询结果作为接收方的 MAC 地址 路由器也有 ARP 缓存, 类似于计算机中的过程
  • 接下里是发送发 MAC 地址, 这里写输出端口的 MAC 地址; 以太类型字段, 填写 0800 (16进制) 代表 IP 协议
  • 网络包完成后, 接下来将其转换成电信号通过端口发送出去
  • 发出去去的网络包又会通过交换机到达下一个路由器, 然后下一个路由器发往下下个路由器, 层层转发之后, 网络包到达目的地

发送过程中, 源 IP 和 目标 IP 是不会变的, 变化的是 MAC 地址 使用 MAC 地址在以太网进行两个设备之间的包传输.

数据至此已经送达目的地

互相解包 — 客户端 和 服务器

image-20220614112556615
  • 数据包抵达服务器之后, 服务器扒开 MAC 头部, 确认是否符合
  • 扒开数据包的 IP 头, 发现 IP 地址符合, 根据 IP 头中的 协议项, 知道是 TCP 协议
  • 再扒开 TCP 的头, 看看序列号是不是所需要的, 是的话就存入缓存然后返回一个 ACK, 如果不是就丢弃, TCP 头部还有端口号, HTTP 服务正在监听这个端口号, 于是服务器就会将这个包发送给 HTTP 进程
  • 服务器的 HTTP 进程看到, 请求是要访问页面, 于是就把页面封装到 HTTP 响应报文里.
  • HTTP 响应报文穿上 TCP, IP, MAC 头部后准备发送, 不过这次发送和接收的 IP 地址互换了.
  • 然后类似于 HTTP 请求 来的过程, 从网卡出去, 由交换机转发到路由器, 路由器到下一个路由器, 最后发送到目标路由器, 发送给以太网的交换机, 再由交换机发给客户端
  • 然后客户端开始扒皮, 扒到只剩 HTTP 响应报文后, 就交给对应的浏览器渲染画面, 这样一份特别的数据包快递就显示出来了.
  • 最后 客户端 要离开了, 向服务器发起 TCP 四次挥手, 只有双方的链接就断开了.

一些问题

笔记本有交换机吗? 交换机是什么?

笔记本没有交换机, 但是笔记本都配备了无限网络交换机.

交换机通常包含两个网口以上, 现在的路由器基本都配备了交换机的功能. 一般用于以太网内的设备互相通信, 交换数据.

ARP 协议获取的 MAC 地址只能获取到内网的 MAC 地址?

是的, 填写 MAC 地址时, 如果目标主机不是局域网内的设备, 填入的 MAC 地址就是路由器的 MAC 地址, 也就是将数据包传输给路由器, 路由器传给下一个路由器, 直到目标主机局域网内的路由器, 发现 IP 地址是局域网内的主机, 就会使用 ARP 请求获取目标主机的 MAC 地址, 然后发送到主机.

还是那句话, 源 IP 地址 和 目标 IP 地址是不会变的, 变化的是中途使用的源 MAC 地址和目标 MAC 地址.


Linux 系统如何收发网络包?

OSI 和 TCP/IP 网络模型

国际标准化组织规定的 OSI 七层模型如下

  • 应用层, 负责给应用程序提供统一的接口;
  • 表示层, 负责把数据转换成兼容另一个系统能识别的格式;
  • 会话层, 负责建立、管理和终止表示层实体之间的通信会话;
  • 传输层, 负责端到端的数据传输;
  • 网络层, 负责数据的路由, 转发, 分片;
  • 数据链路层, 负责数据的封帧, 差错检测, MAC 寻址;
  • 物理层, 负责在物理网络中传输数据帧;

OSI 模型过于复杂, 分层也是概念上的分层, 没有具体实现方案.

实际上我们比较常见的是四层模型 TCP/IP 网络模型, Linux 正是使用这套网络模型作为网络协议栈. TCP/IP 模型一共四层

  • 应用层, 负责向用户提供一组应用程序, 如 HTTP, DNS, FTP 等;
  • 传输层, 负责端到端的通信, 如 TCP, UDP 等;
  • 网络层, 负责网络包的封装, 路由, 转发, 分片, 如 IP, ICMP 等;
  • 网络接口层, 负责网络包在物理网络中的传输, 如封帧, 差错检测, MAC 寻址, 通过网卡传输网络帧等;

两者关系如图

image-20220618175320395

Linux 网络协议栈

image-20220604214129271
  • 传输层, 增加了 TCP 头.
  • 网络层, 再增加了 IP 头.
  • 网络接口层, 再增加了 帧头 和 帧尾.

封装了很多头部的数据包也是有相应长度规定的, 因为数据链路层不能传输任意大小的数据包, 在以太网中, 规定最大传输单元 MTU 是 1500 字节.

当网络包超过 MTU 的大小, 就会在网络层分片. 如果 MTU 规定的越小, 那么需要分包就越多, 网络吞吐能力越差; 反之, 如果 MTU 规定得越大, 需要的分包也就越小, 那么网络吞吐能力就越好.

关于 MTU 的大小是如何规定的, 主要是影响因素有 网络类型(Ethernet, IEEE 802.4等), 链路介质(因为 MTU 在数据链路层), 不同厂商, 同一厂商的不同产品型号等因素.

具体情况可参考什么是MTU(Maximum Transmission Unit)?MTU设置为多少合适? – 华为 (huawei.com)

所以 Linux 协议栈如下图, 类似于 TCP/IP 的四层结构

image-20220618182922181

从上面的协议栈可以看出

  • 应用程序通过系统调用, 跟 Socket 层进行数据交互;
  • Socket 层下面就是传输层, 网络层, 网络接口层;
  • 最下面一层, 是网卡驱动和网卡;

ICMP 协议就是一个 错误侦测与回报机制.

主要用于在主机与路由器之间传递控制信息,包括报告错误、交换受限控制和状态信息等.

当遇到 IP 数据无法访问目标、IP 路由器无法按当前的传输速率转发数据包等情况时,会自动发送 ICMP 消息.

ping 和 tracert 是两个常用网络管理命令,ping 用来测试网络可达性,tracert 用来显示到达目的主机的路径。他们都利用 ICMP 协议来实现.

Linux 接收网络包的流程

接收数据

网卡专门负责接收和发送网络包, 当网卡接收到一个网络包后, 就会通过 DMA(Direct Memory Access) 技术, 将网络包存入 Ring Buffer , 一个环形缓冲区.

NAPI 处理机制

网卡会在每收到一个网络包时通过触发中断的方式告诉操作系统. 但网络包数量很多, 触发太多次中断会对 CPU 造成性能影响.

为了解决频繁中断带来的性能开销, Linux 内核在 2.6 版本引入了 NAPI 机制, 简单来说就是 **中断与轮询 **的混合方式接收网络包.核心就是不采用中断的方式读取数据, 而是用中断方式唤醒接收数据的程序, 然后来轮询数据

如, 当有网络包到达时, 网卡会发起硬件中断, 于是会执行中断处理函数, 该函数处理完时需要 暂时屏蔽中断, 唤醒 软中断 来轮询处理数据, 直到没有新数据时才取消屏蔽中断, 一次中断就可以处理多个网络包.

软中断处理网络包的过程, 其实就是从 Ring Buffer 中拷贝数据到内核 struck_sk_buff 缓冲区中, 从而将一个网络包交给协议栈进行逐层处理, 这个处理的过程就是接收网络包的过程. 处理完一次中断中所有的网络包, 这次软中断就完成了.

协议栈逐层处理过程

image-20220619115410966
  • 网络接口层, 检查报文的合法性, 不合法丢弃, 合法就找出上层协议的类型, IPv4 或 IPv6, 然后去除帧头帧尾, 交给网络层;
  • 网络层, 取出 IP 包, 判断下一步走向, 是交给上层处理 还是 转发出去, 当确认是本机处理后, 就会从 IP 头里看上层协议的类型是 TCP 还是 UDP, 然后去掉 IP 头, 交给传输层;
  • 传输层, 取出 TCP 或 UDP 头, 根据 源 IP, 源端口, 目标 IP, 目标端口 作为标识, 找出对应 Socket, 将数据卡拷贝到 Socket 接收缓冲区;
  • 应用程序调用 Socket 接口, 从内核的 Socket 接收缓冲区 读取数据到应用层;

Linux 发送网络包的流程

与接收网络包过程相反

  • 调用 Socket 发送数据包 接口, 也就是系统调用, 用户会陷入内核态中的 Socket 层, Socket 层会将应用层数据拷贝Socket 发送缓冲区中;
  • 网络协议栈从 Socket 发送缓冲区中取出数据包, 按照 TCP/IP 协议栈逐层处理; 如果是 TCP, 那么先增加 TCP 包头, 然后网络层增加 IP 包, 然后查询路由表 确认下一跳 IP, 按照 MTU 进行分片;
  • 分片后到达网络接口层中, 会通过 ARP 获得下一跳的 MAC 地址, 然后增加 帧头和帧尾, 放入发包队列中;
  • 触发中断告诉网卡驱动, 驱动程序通过 DMA, 将发包队列中的网络包 放入 硬件网卡队列中, 然后随物理网卡将其发送出去;
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇