兰州网站推,大理建设局网站,网站建设QQ刷赞,百度数据库主页#xff1a;醋溜马桶圈-CSDN博客 专栏#xff1a;计算机网络原理_醋溜马桶圈的博客-CSDN博客 gitee#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1.传输层协议 UDP
1.1 传输层
1.2 端口号
1.3 UDP 协议
1.3.1 UDP 协议端格式
1.3.2 UDP 的特点
1.3.3 面向数据报
1… 主页醋溜马桶圈-CSDN博客 专栏计算机网络原理_醋溜马桶圈的博客-CSDN博客 giteemnxcc (mnxcc) - Gitee.com 目录 1.传输层协议 UDP
1.1 传输层
1.2 端口号
1.3 UDP 协议
1.3.1 UDP 协议端格式
1.3.2 UDP 的特点
1.3.3 面向数据报
1.3.4 UDP 的缓冲区
1.3.5 UDP 使用注意事项
1.3.6 基于 UDP 的应用层协议
2.传输层协议 TCP
2.1 TCP 协议
2.2 TCP 协议段格式
2.3 确认应答(ACK)机制
2.4 超时重传机制
2.5 连接管理机制
2.5.1 服务端状态转化
2.5.2 理解 TIME_WAIT 状态
2.5.3 解决 TIME_WAIT 状态引起的 bind 失败的方法
2.5.4 理解 CLOSE_WAIT 状态
2.6 滑动窗口
2.7 流量控制
2.9 拥塞控制
2.10 延迟应答
2.11 捎带应答
2.12 面向字节流
2.13 粘包问题
2.14 TCP 异常情况
2.15 TCP 小结
2.16 基于 TCP 应用层协议
2.17 TCP/UDP 对比
3.网络层
3.1 IP 协议
3.2 协议头格式
3.3 网段划分
3.3.1 特殊的 IP 地址
3.3.2 IP 地址的数量限制
3.3.3 私有 IP 地址和公网 IP 地址
3.4 路由
3.5 IP 分片和组装的具体过程
3.5.1 IP数据报
3.5.2 分片与组装的过程
3.5.2.1 分片
1. 检查 MTU 限制
2. 分割数据报
3. 添加 IP 头部
4. 发送分片
3.5.2.2 组装
1. 接收分片
2. 排序与组装
3. 传递给上层协议
3.5.2.3 分片组装场景
4.数据链路层
4.1 认识以太网
4.2 以太网帧格式
4.3 认识 MAC 地址
4.4 认识 MTU
4.4.1 MTU 对 IP 协议的影响
4.4.2 MTU 对 UDP 协议的影响
4.4.3 MTU 对于 TCP 协议的影响
4.4.4 MSS 和 MTU 的关系
4.4.5 查看硬件地址和 MTU
4.5 ARP 协议
4.5.1 ARP 协议的作用
4.5.2 ARP 协议的工作流程
4.5.3 ARP 数据报的格式
4.5.4 ARP 结合协议的过程
4.5.5 ARP 欺骗原理
1. 步骤一
2. 步骤二
3. 步骤三
5.NAT
5.1 NAT技术背景
5.2 NAT IP 转换过程
5.3 NAPT
5.4 NAT 技术的缺陷
6.代理服务器
6.1 NAT 和代理服务器
6.2 正向代理
6.2.1 概述
6.2.2 工作原理
6.2.3 功能特点
6.2.4 应用场景
6.3 反向代理
6.3.1 概述
6.3.2基本原理
6.3.3 应用场景
7.内网穿透
7.1 内网打洞 1.传输层协议 UDP
1.1 传输层
负责数据能够从发送端传输接收端
1.2 端口号
端口号(Port)标识了一个主机上进行通信的不同的应用程序 在 TCP/IP 协议中用 源 IP源端口号目的 IP目的端口号协议号 这样一个五元组来标识一个通信(可以通过 netstat -n 查看) 端口号范围划分 0 - 1023知名端口号HTTPFTPSSH 等这些广为使用的应用层协议他们的端口号都是固定的1024 - 65535操作系统动态分配的端口号客户端程序的端口号就是由操作系统从这个范围分配的 认识知名端口号(Well-Know Port Number) 有些服务器是非常常用的为了使用方便人们约定一些常用的服务器都是用以下这些 固定的端口号 ssh 服务器使用 22 端口 ftp 服务器使用 21 端口 telnet 服务器使用 23 端口 http 服务器, 使用 80 端口 https 服务器使用 443 执行下面的命令可以看到知名端口号 cat /etc/services 我们自己写一个程序使用端口号时要避开这些知名端口号 一个进程是否可以 bind 多个端口号? 可以一个端口号是否可以被多个进程 bind? 不可以 1.3 UDP 协议 1.3.1 UDP 协议端格式 16 位 UDP 长度表示整个数据报(UDP 首部UDP 数据)的最大长度如果校验和出错就会直接丢弃 1.3.2 UDP 的特点
UDP 传输的过程类似于寄信
无连接知道对端的 IP 和端口号就直接进行传输不需要建立连接不可靠没有确认机制没有重传机制如果因为网络故障该段无法发到对方UDP 协议层也不会给应用层返回任何错误信息面向数据报不能够灵活的控制读写数据的次数和数量
1.3.3 面向数据报
应用层交给 UDP 多长的报文UDP 原样发送既不会拆分也不会合并
用 UDP 传输 100 个字节的数据
如果发送端调用一次 sendto发送 100 个字节那么接收端也必须调用对应的一次 recvfrom接收 100 个字节而不能循环调用 10 次 recvfrom每次接收 10 个字节
1.3.4 UDP 的缓冲区
UDP 没有真正意义上的 发送缓冲区调用 sendto 会直接交给内核由内核将数据传给网络层协议进行后续的传输动作UDP 具有接收缓冲区但是这个接收缓冲区不能保证收到的 UDP 报的顺序和发送 UDP 报的顺序一致如果缓冲区满了再到达的 UDP 数据就会被丢弃
UDP 的 socket 既能读也能写这个概念叫做 全双工 1.3.5 UDP 使用注意事项 我们注意到UDP 协议首部中有一个 16 位的最大长度也就是说一个 UDP 能传输的数据最大长度是 64K(包含 UDP 首部) 然而 64K 在当今的互联网环境下是一个非常小的数字 如果我们需要传输的数据超过 64K就需要在应用层手动的分包多次发送并在接收端手动拼装 1.3.6 基于 UDP 的应用层协议 NFS网络文件系统 TFTP简单文件传输协议 DHCP动态主机配置协议 BOOTP启动协议(用于无盘设备启动) DNS域名解析协议 当然,也包括自己写 UDP 程序时自定义的应用层协议 2.传输层协议 TCP 2.1 TCP 协议 TCP 全称为 传输控制协议(Transmission Control Protocol) 人如其名要对数据的传输进行一个详细的控制 2.2 TCP 协议段格式 源/目的端口号表示数据是从哪个进程来,到哪个进程去; 32 位序号/32 位确认号4 位 TCP 报头长度: 表示该 TCP 头部有多少个 32 位 bit(有多少个 4 字节)所以TCP 头部最大长度是 15 * 4 60 6 位标志位 URG紧急指针是否有效 ACK确认号是否有效 PSH提示接收端应用程序立刻从 TCP 缓冲区把数据读走 RST对方要求重新建立连接我们把携带 RST 标识的称为复位报文段 SYN请求建立连接我们把携带 SYN 标识的称为同步报文段 FIN通知对方本端要关闭了我们称携带 FIN 标识的为结束报文段 16 位窗口大小16 位校验和发送端填充CRC 校验接收端校验不通过则认为数据有问题此处的检验和不光包含 TCP 首部也包含 TCP 数据部分16 位紧急指针标识哪部分数据是紧急数据40 字节头部选项 2.3 确认应答(ACK)机制 TCP 将每个字节的数据都进行了编号即为序列号 每一个 ACK 都带有对应的确认序列号意思是告诉发送者我已经收到了哪些数据下一次你从哪里开始发
2.4 超时重传机制 主机 A 发送数据给 B 之后可能因为网络拥堵等原因数据无法到达主机 B如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答就会进行重发
但是主机 A 未收到 B 发来的确认应答也可能是因为 ACK 丢失了 因此主机 B 会收到很多重复数据那么 TCP 协议需要能够识别出那些包是重复的包并且把重复的丢弃掉
这时候我们可以利用前面提到的序列号就可以很容易做到去重的效果 那么如果超时的时间如何确定? 最理想的情况下找到一个最小的时间保证 确认应答一定能在这个时间内返回但是这个时间的长短随着网络环境的不同是有差异的如果超时时间设的太长会影响整体的重传效率如果超时时间设的太短有可能会频繁发送重复的包 TCP 为了保证无论在任何环境下都能比较高性能的通信因此会动态计算这个最大超时时间
Linux 中(BSD Unix 和 Windows 也是如此)超时以 500ms 为一个单位进行控制每次判定超时重发的超时时间都是 500ms 的整数倍如果重发一次之后仍然得不到应答等待 2*500ms 后再进行重传如果仍然得不到应答等待 4*500ms 进行重传依次类推以指数形式递增累计到一定的重传次数TCP 认为网络或者对端主机出现异常强制关闭连接
2.5 连接管理机制
在正常情况下TCP 要经过三次握手建立连接四次挥手断开连接 2.5.1 服务端状态转化
[CLOSED - LISTEN] 服务器端调用 listen 后进入 LISTEN 状态, 等待客户端连接; [LISTEN - SYN_RCVD] 一旦监听到连接请求(同步报文段)就将该连接放入内核等待队列中并向客户端发送 SYN 确认报文[SYN_RCVD - ESTABLISHED] 服务端一旦收到客户端的确认报文就进入ESTABLISHED 状态可以进行读写数据了. [ESTABLISHED - CLOSE_WAIT] 当客户端主动关闭连接(调用 close)服务器会收到结束报文段服务器返回确认报文段并进入 CLOSE_WAIT[CLOSE_WAIT - LAST_ACK] 进入 CLOSE_WAIT 后说明服务器准备关闭连接(需要处理完之前的数据)当服务器真正调用 close 关闭连接时会向客户端发送FIN此时服务器进入 LAST_ACK 状态等待最后一个 ACK 到来(这个 ACK 是客户端确认收到了 FIN) [LAST_ACK - CLOSED] 服务器收到了对 FIN 的 ACK彻底关闭连接客户端状态转化[CLOSED - SYN_SENT] 客户端调用 connect发送同步报文段[SYN_SENT - ESTABLISHED] connect 调用成功则进入 ESTABLISHED 状态开始读写数据[ESTABLISHED - FIN_WAIT_1] 客户端主动调用 close 时向服务器发送结束报文段同时进入 FIN_WAIT_1[FIN_WAIT_1 - FIN_WAIT_2] 客户端收到服务器对结束报文段的确认则进入 FIN_WAIT_2开始等待服务器的结束报文段[FIN_WAIT_2 - TIME_WAIT] 客户端收到服务器发来的结束报文段进入TIME_WAIT并发出 LAST_ACK[TIME_WAIT - CLOSED] 客户端要等待一个 2MSL(Max Segment Life报文最大生存时间)的时间才会进入 CLOSED 状态 下图是 TCP 状态转换的一个汇总 较粗的虚线表示服务端的状态变化情况较粗的实线表示客户端的状态变化情况CLOSED 是一个假想的起始点不是真实状态
2.5.2 理解 TIME_WAIT 状态
现在做一个测试首先启动 server然后启动 client然后用 Ctrl-C 使 server 终止这时马上再运行 server结果是 这是因为虽然 server 的应用程序终止了但 TCP 协议层的连接并没有完全断开因此不能再次监听同样的 server 端口我们用 netstat 命令查看一下 TCP 协议规定主动关闭连接的一方要处于 TIME_ WAIT 状态等待两个MSL(maximum segment lifetime)的时间后才能回到 CLOSED 状态我们使用 Ctrl-C 终止了 server所以 server 是主动关闭连接的一方在TIME_WAIT 期间仍然不能再次监听同样的 server 端口MSL 在 RFC1122 中规定为两分钟但是各操作系统的实现不同, 在 Centos7 和 Ubuntu 上默认配置的值是 60s可以通过 cat /proc/sys/net/ipv4/tcp_fin_timeout 查看 msl 的值 为什么是 TIME_WAIT 的时间是 2MSL?
MSL 是 TCP 报文的最大生存时间因此 TIME_WAIT 持续存在 2MSL 的话 就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失否则服务器立刻重启可能会收到来自上一个进程的迟到的数据但是这种数据很可能是错误的同时也是在理论上保证最后一个报文可靠到达假设最后一个 ACK 丢失那么服务器会再重发一个 FIN这时虽然客户端的进程不在了但是 TCP 连接还在仍然可以重发 LAST_ACK
2.5.3 解决 TIME_WAIT 状态引起的 bind 失败的方法
在 server 的 TCP 连接没有完全断开之前不允许重新监听某些情况下可能是不合理的
服务器需要处理非常大量的客户端的连接每个连接的生存时间可能很短但是每秒都有很大数量的客户端来请求这个时候如果由服务器端主动关闭连接比如某些客户端不活跃就需要被服务器端主动清理掉就会产生大量 TIME_WAIT 连接由于我们的请求量很大就可能导致 TIME_WAIT 的连接数很多每个连接都会占用一个通信五元组源 ip源端口目的 ip目的端口协议其中服务器的 ip 和端口和协议是固定的 如果新来的客户端连接的 ip 和端口号和 TIME_WAIT 占用的链接重复了就会出现问题
使用 setsockopt()设置 socket 描述符的 选项 SO_REUSEADDR 为 1表示允许创建端口号相同但 IP 地址不同的多个 socket 描述符 2.5.4 理解 CLOSE_WAIT 状态
编译运行没有close函数的服务器启动客户端链接查看 TCP 状态, 客户端服务器都为
ESTABLELISHED 状态, 没有问题
然后我们关闭客户端程序, 观察 TCP 状态
tcp 0 0 0.0.0.0:9090 0.0.0.0:* LISTEN 5038/./dict_server
tcp 0 0 127.0.0.1:49958 127.0.0.1:9090 FIN_WAIT2 -
tcp 0 0 127.0.0.1:9090 127.0.0.1:49958 CLOSE_WAIT 5038/./dict_server
此时服务器进入了 CLOSE_WAIT 状态结合我们四次挥手的流程图可以认为四次挥手没有正确完成
小结对于服务器上出现大量的 CLOSE_WAIT 状态原因就是服务器没有正确的关闭socket导致四次挥手没有正确完成这是一个 BUG只需要加上对应的 close 即可解决问题
2.6 滑动窗口
确认应答策略对每一个发送的数据段都要给一个 ACK 确认应答收到 ACK 后再发送下一个数据段
这样做有一个比较大的缺点就是性能较差尤其是数据往返的时间较长的时候 既然这样一发一收的方式性能较低那么我们一次发送多条数据就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了) 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值上图的窗口大小就是 4000 个字节(四个段)发送前四个段的时候不需要等待任何 ACK直接发送收到第一个 ACK 后滑动窗口向后移动继续发送第五个段的数据依次类推操作系统内核为了维护这个滑动窗口需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答只有确认应答过的数据才能从缓冲区删掉窗口越大则网络的吞吐率就越高 那么如果出现了丢包如何进行重传? 这里分两种情况讨论
情况一数据包已经抵达ACK 被丢了 这种情况下部分 ACK 丢了并不要紧因为可以通过后续的 ACK 进行确认
情况二数据包就直接丢了 当某一段报文段丢失之后发送端会一直收到 1001 这样的 ACK就像是在提醒发送端 我想要的是 1001 一样如果发送端主机连续三次收到了同样一个 1001 这样的应答就会将对应的数据 1001 - 2000 重新发送这个时候接收端收到了 1001 之后再次返回的 ACK 就是 7001 了(因为 2001 - 7000)接收端其实之前就已经收到了被放到了接收端操作系统内核的接收缓冲区中
这种机制被称为 高速重发控制(也叫 快重传)
2.7 流量控制
接收端处理数据的速度是有限的如果发送端发的太快导致接收端的缓冲区被打满这个时候如果发送端继续发送就会造成丢包继而引起丢包重传等等一系列连锁反应
因此 TCP 支持根据接收端的处理能力来决定发送端的发送速度这个机制就叫做流量控制(Flow Control)
接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 窗口大小 字段通过 ACK 端通知发送端窗口大小字段越大说明网络的吞吐量越高接收端一旦发现自己的缓冲区快满了就会将窗口大小设置成一个更小的值通知给发送端发送端接受到这个窗口之后就会减慢自己的发送速度如果接收端缓冲区满了就会将窗口置为 0这时发送方不再发送数据但是需要定期发送一个窗口探测数据段使接收端把窗口大小告诉发送端 接收端如何把窗口大小告诉发送端呢?
TCP 首部中有一个 16 位窗口字段就是存放了窗口大小信息
那么问题来了16 位数字最大表示 65535那么 TCP 窗口最大就是 65535 字节么?
实际上TCP 首部 40 字节选项中还包含了一个窗口扩大因子 M实际窗口大小是 窗口字段的值左移 M 位
2.9 拥塞控制
虽然 TCP 有了滑动窗口这个大杀器能够高效可靠的发送大量的数据但是如果在刚开始阶段就发送大量的数据仍然可能引发问题
因为网络上有很多的计算机可能当前的网络状态就已经比较拥堵在不清楚当前网络状态下贸然发送大量的数据是很有可能引起雪上加霜的
TCP 引入 慢启动 机制先发少量的数据探探路摸清当前的网络拥堵状态再决定按照多大的速度传输数据 此处引入一个概念称为拥塞窗口 发送开始的时候, 定义拥塞窗口大小为 1每次收到一个 ACK 应答, 拥塞窗口加 1每次发送数据包的时候将拥塞窗口和接收端主机反馈的窗口大小做比较取较小的值作为实际发送的窗口
像上面这样的拥塞窗口增长速度是指数级别的慢启动 只是指初使时慢但是增长速度非常快
为了不增长的那么快因此不能使拥塞窗口单纯的加倍此处引入一个叫做慢启动的阈值 当拥塞窗口超过这个阈值的时候不再按照指数方式增长而是按照线性方式增长 当 TCP 开始启动的时候启动阈值等于窗口最大值在每次超时重发的时候慢启动阈值会变成原来的一半同时拥塞窗口置回 1少量的丢包我们仅仅是触发超时重传大量的丢包我们就认为网络拥塞当 TCP 通信开始后网络吞吐量会逐渐上升随着网络发生拥堵吞吐量会立刻下降拥塞控制归根结底是 TCP 协议想尽可能快的把数据传输给对方但是又要避免给网络造成太大压力的折中方案
2.10 延迟应答 如果接收数据的主机立刻返回 ACK 应答这时候返回的窗口可能比较小
假设接收端缓冲区为 1M一次收到了 500K 的数据如果立刻应答返回的窗口就是 500K但实际上可能处理端处理的速度很快10ms 之内就把 500K 数据从缓冲区消费掉了在这种情况下接收端处理还远没有达到自己的极限即使窗口再放大一些也能处理过来如果接收端稍微等一会再应答比如等待 200ms 再应答那么这个时候返回的窗口大小就是 1M
一定要记得窗口越大网络吞吐量就越大传输效率就越高我们的目标是在保证网络不拥塞的情况下尽量提高传输效率
那么所有的包都可以延迟应答么? 肯定也不是 数量限制每隔 N 个包就应答一次时间限制超过最大延迟时间就应答一次 具体的数量和超时时间依操作系统不同也有差异 一般 N 取 2超时时间取 200ms 2.11 捎带应答
在延迟应答的基础上我们发现很多情况下客户端服务器在应用层也是 一发一收 的意味着客户端给服务器说了 How are you服务器也会给客户端回一个 Fine, thank you
那么这个时候 ACK 就可以搭顺风车和服务器回应的 Fine, thank you 一起回给客户端 2.12 面向字节流
创建一个 TCP 的 socket, 同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区;
调用 write 时数据会先写入发送缓冲区中如果发送的字节数太长会被拆分成多个 TCP 的数据包发出如果发送的字节数太短就会先在缓冲区里等待等到缓冲区长度差不多了或者其他合适的时机发送出去接收数据的时候数据也是从网卡驱动程序到达内核的接收缓冲区然后应用程序可以调用 read 从接收缓冲区拿数据另一方面TCP 的一个连接既有发送缓冲区也有接收缓冲区那么对于这一个连接既可以读数据也可以写数据这个概念叫做 全双工
由于缓冲区的存在TCP 程序的读和写不需要一一匹配例如:
写 100 个字节数据时可以调用一次 write 写 100 个字节也可以调用 100 次 write每次写一个字节读 100 个字节数据时也完全不需要考虑写的时候是怎么写的既可以一次 read 100 个字节也可以一次 read 一个字节重复 100 次
2.13 粘包问题
首先要明确, 粘包问题中的 包是指的应用层的数据包在 TCP 的协议头中没有如同 UDP 一样的 报文长度 这样的字段但是有一个序号这样的字段站在传输层的角度TCP 是一个一个报文过来的按照序号排好序放在缓冲区中站在应用层的角度看到的只是一串连续的字节数据那么应用程序看到了这么一连串的字节数据就不知道从哪个部分开始到哪个部分是一个完整的应用层数据包
那么如何避免粘包问题呢? 归根结底就是一句话明确两个包之间的边界
对于定长的包保证每次都按固定大小读取即可例如上面的 Request 结构是固定大小的那么就从缓冲区从头开始按 sizeof(Request)依次读取即可对于变长的包可以在包头的位置约定一个包总长度的字段从而就知道了包的结束位置对于变长的包还可以在包和包之间使用明确的分隔符(应用层协议是程序猿自己来定的只要保证分隔符不和正文冲突即可)
思考对于 UDP 协议来说是否也存在 粘包问题 呢?
对于 UDP如果还没有上层交付数据UDP 的报文长度仍然在同时UDP 是一个一个把数据交付给应用层就有很明确的数据边界站在应用层的站在应用层的角度使用 UDP 的时候要么收到完整的 UDP 报文要么不收不会出现半个的情况.
2.14 TCP 异常情况
进程终止进程终止会释放文件描述符仍然可以发送 FIN和正常关闭没有什么区别机器重启和进程终止的情况相同机器掉电/网线断开接收端认为连接还在一旦接收端有写入操作接收端发现连接已经不在了就会进行 reset即使没有写入操作TCP 自己也内置了一个保活定时器会定期询问对方是否还在如果对方不在也会把连接释放另外应用层的某些协议也有一些这样的检测机制例如 HTTP 长连接中也会定期检测对方的状态例如 QQ在 QQ 断线之后也会定期尝试重新连接 2.15 TCP 小结 为什么 TCP 这么复杂? 因为要保证可靠性同时又尽可能的提高性能 可靠性 校验和 序列号(按序到达) 确认应答 超时重发 连接管理 流量控制 拥塞控制 提高性能 滑动窗口 快速重传 延迟应答 捎带应答 其他 定时器(超时重传定时器保活定时器TIME_WAIT 定时器等) 2.16 基于 TCP 应用层协议 HTTP HTTPS SSH Telnet FTP SMTP 当然也包括你自己写 TCP 程序时自定义的应用层协议 2.17 TCP/UDP 对比 我们说了 TCP 是可靠连接那么是不是 TCP 一定就优于 UDP 呢? TCP 和 UDP 之间的优点和缺点不能简单绝对的进行比较 TCP 用于可靠传输的情况应用于文件传输重要状态更新等场景UDP 用于对高速传输和实时性要求较高的通信领域例如早期的 QQ、视频传输等另外 UDP 可以用于广播 归根结底TCP 和 UDP 都是程序员的工具什么时机用具体怎么用还是要根据具体的需求场景去判定 3.网络层 在复杂的网络环境中确定一个合适的路径 3.1 IP 协议 主机配有 IP 地址但是不进行路由控制的设备路由器即配有 IP 地址又能进行路由控制节点主机和路由器的统称 3.2 协议头格式 4 位版本号(version) 指定 IP 协议的版本对于 IPv4 来说就是 44 位头部长度(header length) IP 头部的长度是多少个 32bit也就是 length 4 的字节数4bit 表示最大的数字是 15因此 IP 头部最大长度是 60 字节8 位服务类型(Type Of Service) 3 位优先权字段(已经弃用)4 位 TOS 字段和 1 位保留字段(必须置为 0)4 位 TOS 分别表示最小延时最大吞吐量最高可靠性最小成本这四者相互冲突只能选择一个对于 ssh/telnet 这样的应用程序最小延时比较重要对于 ftp 这样的程序最大吞吐量比较重要16 位总长度(total length) IP 数据报整体占多少个字节16 位标识(id) 唯一的标识主机发送的报文如果 IP 报文在数据链路层被分片了那么每一个片里面的这个 id 都是相同的3 位标志字段 第一位保留(保留的意思是现在不用但是还没想好说不定以后要用到)第二位置为 1 表示禁止分片这时候如果报文长度超过 MTUIP 模块就会丢弃报文第三位表示更多分片如果分片了的话最后一个分片置为 0其他是 1类似于一个结束标记13 位分片偏移(framegament offset) 是分片相对于原始 IP 报文开始处的偏移其实就是在表示当前分片在原报文中处在哪个位置实际偏移的字节数是这个值 8 得到的因此除了最后一个报文之外其他报文的长度必须是 8 的整数倍(否则报文就不连续了)8 位生存时间(Time To Live, TTL) 数据报到达目的地的最大报文跳数一般是64每次经过一个路由TTL - 1一直减到 0 还没到达那么就丢弃了这个字段主要是用来防止出现路由循环 8 位协议 表示上层协议的类型 16 位头部校验和 使用 CRC 进行校验来鉴别头部是否损坏32 位源地址和 32 位目标地址 表示发送端和接收端选项字段(不定长最多 40 字节)
3.3 网段划分
IP 地址分为两个部分网络号和主机号
网络号保证相互连接的两个网段具有不同的标识主机号同一网段内主机之间具有相同的网络号但是必须有不同的主机号 不同的子网其实就是把网络号相同的主机放到一起如果在子网中新增一台主机则这台主机的网络号和这个子网的网络号一致但是主机号必须不能和子网中的其他主机重复
通过合理设置主机号和网络号就可以保证在相互连接的网络中每台主机的 IP 地址都不相同
那么问题来了手动管理子网内的 IP是一个相当麻烦的事情
有一种技术叫做 DHCP能够自动的给子网内新增主机节点分配 IP 地址避免了手动管理 IP 的不便一般的路由器都带有 DHCP 功能因此路由器也可以看做一个 DHCP 服务器
过去曾经提出一种划分网络号和主机号的方案把所有 IP 地址分为五类如下图所示 A 类 0.0.0.0 到 127.255.255.255 B 类 128.0.0.0 到 191.255.255.255 C 类 192.0.0.0 到 223.255.255.255 D 类 224.0.0.0 到 239.255.255.255 E 类 240.0.0.0 到 247.255.255.255 随着 Internet 的飞速发展这种划分方案的局限性很快显现出来大多数组织都申请 B 类网络地址导致 B 类地址很快就分配完了而 A 类却浪费了大量地址
例如申请了一个 B 类地址理论上一个子网内能允许 6 万 5 千多个主机A 类地址的子网内的主机数更多实际网络架设中不会存在一个子网内有这么多的情况因此大量的 IP 地址都被浪费掉了 针对这种情况提出了新的划分方案称为 CIDR(Classless Interdomain Routing) 引入一个额外的子网掩码(subnet mask)来区分网络号和主机号子网掩码也是一个 32 位的正整数通常用一串 0 来结尾将 IP 地址和子网掩码进行 按位与 操作得到的结果就是网络号网络号和主机号的划分与这个 IP 地址是 A 类、B 类还是 C 类无关 可见IP 地址与子网掩码做与运算可以得到网络号主机号从全 0 到全 1 就是子网的地址范围 IP 地址和子网掩码还有一种更简洁的表示方法例如 140.252.20.68/24表示 IP 地址为 140.252.20.68子网掩码的高 24 位是 1也就是 255.255.255.0 3.3.1 特殊的 IP 地址 将 IP 地址中的主机地址全部设为 0就成为了网络号代表这个局域网将 IP 地址中的主机地址全部设为 1就成为了广播地址用于给同一个链路中相互连接的所有主机发送数据包127.*的 IP 地址用于本机环回(loop back)测试通常是 127.0.0.1 3.3.2 IP 地址的数量限制
我们知道IP 地址(IPv4)是一个 4 字节 32 位的正整数那么一共只有 2 的 32 次方 个 IP地址大概是 43 亿左右而 TCP/IP 协议规定每个主机都需要有一个 IP 地址
这意味着一共只有 43 亿台主机能接入网络么?
实际上由于一些特殊的 IP 地址的存在数量远不足 43 亿另外 IP 地址并非是按照主机台数来配置的而是每一个网卡都需要配置一个或多个 IP 地址
CIDR 在一定程度上缓解了 IP 地址不够用的问题(提高了利用率减少了浪费但是 IP 地址的绝对上限并没有增加)仍然不是很够用这时候有三种方式来解决
动态分配 IP 地址只给接入网络的设备分配 IP 地址因此同一个 MAC 地址的设备每次接入互联网中得到的 IP 地址不一定是相同的; NAT 技术IPv6IPv6 并不是 IPv4 的简单升级版这是互不相干的两个协议彼此并不兼容IPv6 用 16 字节 128 位来表示一个 IP 地址但是目前 IPv6 还没有普及
3.3.3 私有 IP 地址和公网 IP 地址
如果一个组织内部组建局域网IP 地址只用于局域网内的通信而不直接连到 Internet 上理论上使用任意的 IP 地址都可以但是 RFC 1918 规定了用于组建局域网的私有 IP 地址
10.*前 8 位是网络号共 16,777,216 个地址 172.16.*到 172.31.*前 12 位是网络号共 1,048,576 个地址 192.168.*前 16 位是网络号共 65,536 个地址
包含在这个范围中的都成为私有 IP其余的则称为全局 IP(或公网 IP) 一个路由器可以配置两个 IP 地址一个是 WAN 口 IP一个是 LAN 口 IP(子网IP)路由器 LAN 口连接的主机都从属于当前这个路由器的子网中不同的路由器子网 IP 其实都是一样的(通常都是 192.168.1.1)子网内的主机IP 地址不能重复但是子网之间的 IP 地址就可以重复了每一个家用路由器其实又作为运营商路由器的子网中的一个节点这样的运营商路由器可能会有很多级最外层的运营商路由器WAN 口 IP 就是一个公网 IP 了子网内的主机需要和外网进行通信时路由器将 IP 首部中的 IP 地址进行替换(替换成 WAN 口 IP)这样逐级替换最终数据包中的 IP 地址成为一个公网 IP这种技术称为 NAT(Network Address Translation网络地址转换)如果希望我们自己实现的服务器程序能够在公网上被访问到就需要把程序部署在一台具有外网 IP 的服务器上这样的服务器可以在阿里云/腾讯云上进行购买
3.4 路由
在复杂的网络结构中找出一条通往终点的路线
路由的过程就是这样一跳一跳(Hop by Hop) 问路 的过程
所谓 一跳 就是数据链路层中的一个区间具体在以太网中指从源 MAC 地址到目的 MAC 地址之间的帧传输区间 IP 数据包的传输过程和问路一样
当 IP 数据包到达路由器时路由器会先查看目的 IP路由器决定这个数据包是能直接发送给目标主机还是需要发送给下一个路由器依次反复一直到达目标 IP 地址
那么如何判定当前这个数据包该发送到哪里呢? 这个就依靠每个节点内部维护一个路由表 路由表可以使用 route 命令查看 如果目的 IP 命中了路由表就直接转发即可路由表中的最后一行主要由下一跳地址和发送接口两部分组成当目的地址与路由表中其它行都不匹配时就按缺省路由条目规定的接口发送到下一跳地址 假设某主机上的网络接口配置和路由表如下 这台主机有两个网络接口一个网络接口连到 192.168.10.0/24 网络另一个网络接口连到 192.168.56.0/24 网络路由表的 Destination 是目的网络地址Genmask 是子网掩码Gateway 是下一跳地址Iface 是发送接口Flags 中的 U 标志表示此条目有效(可以禁用某些 条目)G 标志表示此条目的下一跳地址是某个路由器的地址没有 G 标志的条目表示目的网络地址是与本机接口直接相连的网络不必经路由器转发
转发过程例 1如果要发送的数据包的目的地址是 192.168.56.3 跟第一行的子网掩码做与运算得 到 192.168.56.0与第一行的目的网络地址不符 再跟第二行的子网掩码做与运算得 到 192.168.56.0正是第二行的目的网络地址因此从 eth1 接口发送出去由于 192.168.56.0/24 正 是与 eth1 接口直接相连的网络因此可以直接发到目的主机不需要经路由器转发 转发过程例 2如果要发送的数据包的目的地址是 202.10.1.2 依次和路由表前几项进行对比发现都不匹配按缺省路由条目从 eth0 接口发出去发往 192.168.10.1 路由器由 192.168.10.1 路由器根据它的路由表决定下一跳地址 3.5 IP 分片和组装的具体过程
3.5.1 IP数据报 16 位标识(id)唯一的标识主机发送的报文如果 IP 报文在数据链路层被分片了那么每一个片里面的这个 id 都是相同的3 位标志字段 第一位保留(保留的意思是现在不用但是还没想好说不定以后要用到)第二位置为 1 表示禁止分片这时候如果报文长度超过 MTUIP 模块就会丢弃报文第三位表示更多分片如果分片了的话最后一个分片置为 0其他是 1类似于一个结束标记13 位分片偏移(framegament offset) 是分片相对于原始 IP 报文开始处的偏移其实就是在表示当前分片在原报文中处在哪个位置实际偏移的字节数是这个值除以 8 得到的因此除了最后一个报文之外(之前如果都是 8 的整数倍最后一片的偏移量也一定是 8 的整数倍)其他报文的长度必须是 8 的整数倍(否则报文就不连续了)
注意片偏移(13 位)表示本片数据在它所属的原始数据报数据区中的偏移量以 8 字节为单位
3.5.2 分片与组装的过程
3.5.2.1 分片
1. 检查 MTU 限制
当一个 IP 数据报的大小超过了网络的 MTU最大传输单元限制时就需要进行分片。MTU 是数据链路层对 IP 层数据包进行封装时所能接受的最大数据长度
2. 分割数据报
IP 层将原始的 IP 数据报分割成多个较小的片段对于每个片段IP 层会设置相应的标识Identification、偏移量Fragment Offset和标志位Flags等字段标识字段用于标识属于同一个数据报的不同分片确保所有分片能够被正确地重新组装偏移量字段指示了当前分片相对于原始数据报的起始位置以 8 字节为单位标志位字段包含了 3 个位其中 MFMore Fragment位用于指示是否还有更多的分片DFDo Not Fragment位用于指示数据报是否允许进行分片
3. 添加 IP 头部
每个分片都会加上自己的 IP 头部与完整 IP 报文拥有类似的 IP 头结构但 MF 和 Fragment Offset 等字段的值会有所不同
4. 发送分片
分片在传输过程中独立传输每个分片都有自己的 IP 头部并且各自独立地选择路由
3.5.2.2 组装
1. 接收分片
当目的主机的 IP 层接收到这些分片后会根据标识字段将属于同一个数据报的所有分片挑选出来
2. 排序与组装
利用片偏移字段IP 层会对属于同一个数据报的分片进行排序当所有的分片都到达并正确排序后IP 层会将这些分片重新组装成一个完整的 IP 数据报
3. 传递给上层协议
组装好的 IP 数据报会传递给上层的协议进行处理
3.5.2.3 分片组装场景 4.数据链路层
用于两个设备(同一种数据链路节点)之间进行传递
4.1 认识以太网
以太网 不是一种具体的网络而是一种技术标准既包含了数据链路层的内容也包含了一些物理层的内容例如规定了网络拓扑结构、访问控制方式、传输速率等例如以太网中的网线必须使用双绞线传输速率有 10M100M1000M 等以太网是当前应用最广泛的局域网技术和以太网并列的还有令牌环网无线LAN 等
4.2 以太网帧格式
以太网的帧格式如下所示 源地址和目的地址是指网卡的硬件地址(也叫 MAC 地址)长度是 48 位是在网卡出厂时固化的帧协议类型字段有三种值分别对应 IP、ARP、RARP帧末尾是 CRC 校验码
4.3 认识 MAC 地址
MAC 地址用来识别数据链路层中相连的节点长度为 48 位, 及 6 个字节一般用 16 进制数字加上冒号的形式来表示 (例如:08:00:27:03:fb:19) 在网卡出厂时就确定了不能修改mac 地址通常是唯一的(虚拟机中的 mac 地址不是真实的 mac 地址可能会冲突也有些网卡支持用户配置 mac 地址) IP 地址描述的是路途总体的 起点 和 终点MAC 地址描述的是路途上的每一个区间的起点和终点 4.4 认识 MTU
MTU 相当于发快递时对包裹尺寸的限制这个限制是不同的数据链路对应的物理层产生的限制
以太网帧中的数据长度规定最小 46 字节最大 1500 字节ARP 数据包的长度不够 46 字节要在后面补填充位最大值 1500 称为以太网的最大传输单元(MTU)不同的网络类型有不同的 MTU如果一个数据包从以太网路由到拨号链路上数据包长度大于拨号链路的 MTU 了则需要对数据包进行分片(fragmentation)不同的数据链路层标准的 MTU 是不同的
4.4.1 MTU 对 IP 协议的影响
由于数据链路层 MTU 的限制对于较大的 IP 数据包要进行分包
将较大的 IP 包分成多个小包并给每个小包打上标签每个小包 IP 协议头的 16 位标识(id) 都是相同的每个小包的 IP 协议头的 3 位标志字段中第 2 位置为 0表示允许分片第 3 位来表示结束标记(当前是否是最后一个小包是的话置为 1否则置为 0)到达对端时再将这些小包会按顺序重组拼装到一起返回给传输层一旦这些小包中任意一个小包丢失接收端的重组就会失败但 IP 层不会负责重新传输数据 4.4.2 MTU 对 UDP 协议的影响
一旦 UDP 携带的数据超过 1472(1500 - 20(IP 首部) - 8(UDP 首部))那么就会在网络层分成多个 IP 数据报这多个 IP 数据报有任意一个丢失都会引起接收端网络层重组失败那么这就意味着如果 UDP 数据报在网络层被分片整个数据被丢失的概率就大大增加了
4.4.3 MTU 对于 TCP 协议的影响
TCP 的一个数据报也不能无限大还是受制于 MTU. TCP 的单个数据报的最大消息长度称为 MSS(Max Segment Size)TCP 在建立连接的过程中通信双方会进行 MSS 协商最理想的情况下MSS 的值正好是在 IP 不会被分片处理的最大长度(这个长度仍然是受制于数据链路层的 MTU)双方在发送 SYN 的时候会在 TCP 头部写入自己能支持的 MSS 值然后双方得知对方的 MSS 值之后选择较小的作为最终 MSSMSS 的值就是在 TCP 首部的 40 字节变长选项中(kind2)
4.4.4 MSS 和 MTU 的关系 4.4.5 查看硬件地址和 MTU 使用 ifconfig 命令即可查看 ip 地址 mac 地址 和 MTU
4.5 ARP 协议
虽然我们在这里介绍 ARP 协议但是需要强调ARP 不是一个单纯的数据链路层的协议而是一个介于数据链路层和网络层之间的协议
4.5.1 ARP 协议的作用
ARP 协议建立了主机 IP 地址 和 MAC 地址 的映射关系
在网络通讯时源主机的应用程序知道目的主机的 IP 地址和端口号却不知道目的主机的硬件地址数据包首先是被网卡接收到再去处理上层协议的如果接收到的数据包的硬件地址与本机不符则直接丢弃因此在通讯前必须获得目的主机的硬件地址
4.5.2 ARP 协议的工作流程 源主机发出 ARP 请求询问“IP 地址是 192.168.0.1 的主机的硬件地址是多少”并将这个请求广播到本地网段(以太网帧首部的硬件地址填 FF:FF:FF:FF:FF:FF 表示广播)目的主机接收到广播的 ARP 请求发现其中的 IP 地址与本机相符则发送一个 ARP 应答数据包给源主机将自己的硬件地址填写在应答包中每台主机都维护一个 ARP 缓存表,可以用 arp -a 命令查看。缓存表中的表项有过期时间(一般为 20 分钟)如果 20 分钟内没有再次使用某个表项则该表项失效下次还要发 ARP 请求来获得目的主机的硬件地址 4.5.3 ARP 数据报的格式 注意到源 MAC 地址、目的 MAC 地址在以太网首部和 ARP 请求中各出现一次对于链路层为以太网的情况是多余的但如果链路层是其它类型的网络则有可能是必要的硬件类型指链路层网络类型1 为以太网协议类型指要转换的地址类型0x0800 为 IP 地址硬件地址长度对于以太网地址为 6 字节协议地址长度对于和 IP 地址为 4 字节op 字段为 1 表示 ARP 请求op 字段为 2 表示 ARP 应答
4.5.4 ARP 结合协议的过程 注意到源 MAC 地址、目的 MAC 地址在以太网首部和 ARP 请求中各出现一次对于链路层为以太网的情况是多余的但如果链路层是其它类型的网络则有可能是必要的硬件类型指链路层网络类型,1 为以太网协议类型指要转换的地址类型,0x0800 为 IP 地址硬件地址长度对于以太网地址为 6 字节协议地址长度对于和 IP 地址为 4 字节op 字段为 1 表示 ARP 请求op 字段为 2 表示 ARP 应答 完成 ARP 的过程 4.5.5 ARP 欺骗原理
1. 步骤一 2. 步骤二 3. 步骤三 5.NAT
5.1 NAT技术背景
IPv4 协议中IP 地址数量不充足
NAT 技术当前解决 IP 地址不够用的主要手段是路由器的一个重要功能
NAT 能够将私有 IP 对外通信时转为全局 IP也就是就是一种将私有 IP 和全局 IP 相互转化的技术方法很多学校 家庭 公司内部采用每个终端设置私有 IP, 而在路由器或必要的服务器上设置全局 IP全局 IP 要求唯一但是私有 IP 不需要在不同的局域网中出现相同的私有 IP 是完全不影响的
5.2 NAT IP 转换过程 NAT 路由器将源地址从 10.0.0.10 替换成全局的 IP 202.244.174.37NAT 路由器收到外部的数据时又会把目标 IP 从 202.244.174.37 替换回10.0.0.10在 NAT 路由器内部有一张自动生成的用于地址转换的表当 10.0.0.10 第一次向 163.221.120.9 发送数据时就会生成表中的映射关系
5.3 NAPT
那么问题来了如果局域网内有多个主机都访问同一个外网服务器那么对于服务器返回的数据中目的 IP 都是相同的那么 NAT 路由器如何判定将这个数据包转发给哪个局域网的主机?
这时候 NAPT 来解决这个问题了使用 IPport 来建立这个关联关系 这种关联关系也是由 NAT 路由器自动维护的例如在 TCP 的情况下建立连接时就会生成这个表项在断开连接后就会删除这个表项
5.4 NAT 技术的缺陷
由于 NAT 依赖这个转换表所以有诸多限制
无法从 NAT 外部向内部服务器建立连接装换表的生成和销毁都需要额外开销通信过程中一旦 NAT 设备异常即使存在热备所有的 TCP 连接也都会断开
6.代理服务器
6.1 NAT 和代理服务器
路由器往往都具备 NAT 设备的功能通过 NAT 设备进行中转完成子网设备和其他子网设备的通信过程
代理服务器看起来和 NAT 设备有一点像客户端像代理服务器发送请求代理服务器将请求转发给真正要请求的服务器服务器返回结果后代理服务器又把结果回传给客户端
那么 NAT 和代理服务器的区别有哪些呢?
从应用上讲NAT 设备是网络基础设备之一解决的是 IP 不足的问题代理服务器则是更贴近具体应用比如通过代理服务器进行翻墙另外像迅游这样的加速器也是使用代理服务器从底层实现上讲NAT 是工作在网络层直接对 IP 地址进行替换代理服务器往往工作在应用层从使用范围上讲NAT 一般在局域网的出口部署代理服务器可以在局域网做也可以在广域网做也可以跨网从部署位置上看NAT 一般集成在防火墙路由器等硬件设备上代理服务器则是一个软件程序需要部署在服务器
代理服务器是一种应用比较广的技术
翻墙广域网中的代理负载均衡局域网中的代理
代理服务器又分为正向代理和反向代理.
代购例子 C 花王尿不湿是一个很经典的尿不湿品牌产自日本 我自己去日本买尿不湿比较不方便但是可以让我在日本工作的表姐去超市买了快递给我此时超市看到的买家是我表姐我的表姐就是 正向代理 后来找我表姐买尿不湿的人太多了我表姐觉得天天去超市太麻烦干脆去超市买了一大批尿不湿屯在家里如果有人来找她代购就直接把屯在家里的货发出去而不必再去超市此时我表姐就是 反向代理 正向代理用于请求的转发(例如借助代理绕过反爬虫)
反向代理往往作为一个缓存
6.2 正向代理
6.2.1 概述
正向代理Forward Proxy是一种常见的网络代理方式它位于客户端和目标服务器之间代表客户端向目标服务器发送请求。正向代理服务器接收客户端的请求然后将请求转发给目标服务器最后将目标服务器的响应返回给客户端。通过这种方式正向代理可以实现多种功能如提高访问速度、隐藏客户端身份、实施访问控制等。 6.2.2 工作原理
客户端将请求发送给正向代理服务器正向代理服务器接收请求并根据配置进行处理如缓存查找、内容过滤等正向代理服务器将处理后的请求转发给目标服务器目标服务器处理请求并将响应返回给正向代理服务器正向代理服务器将响应返回给客户端
6.2.3 功能特点
缓存功能正向代理服务器可以缓存经常访问的资源当客户端再次请求这些资源时可以直接从缓存中获取提高访问速度内容过滤正向代理可以根据预设的规则对请求或响应进行过滤如屏蔽广告、阻止恶意网站等访问控制通过正向代理可以实现对特定网站的访问控制如限制员工在工作时间访问娱乐网站隐藏客户端身份正向代理可以隐藏客户端的真实 IP 地址保护客户端的隐私负载均衡在多个目标服务器之间分配客户端请求提高系统的可扩展性和可靠性
6.2.4 应用场景
企业网络管理企业可以通过正向代理实现对员工网络访问的管理和控制确保员工在工作时间内专注于工作避免访问不良网站或泄露公司机密公共网络环境在公共场所如图书馆、学校等提供的网络环境中通过正向代理可以实现对网络资源的合理分配和管理确保网络使用的公平性和安全性内容过滤与保护家长可以通过设置正向代理来过滤不良内容保护孩子免受网络上的不良信息影响提高访问速度对于经常访问的网站或资源正向代理可以通过缓存机制提高访问速度减少网络延迟跨境电商与海外访问对于跨境电商或需要访问海外资源的企业和个人正向代理可以帮助他们突破网络限制顺畅地访问海外网站和资源
6.3 反向代理
6.3.1 概述
反向代理服务器是一种网络架构模式其作为 Web 服务器的前置服务器接收来自客户端的请求并将这些请求转发给后端服务器然后将后端服务器的响应返回给客户端。这种架构模式可以提升网站性能、安全性和可维护性等 6.3.2基本原理
反向代理服务器位于客户端和 Web 服务器之间当客户端发起请求时它首先会到达反向代理服务器。反向代理服务器会根据配置的规则将请求转发给后端的 Web 服务器并将 Web 服务器的响应返回给客户端。在这个过程中客户端并不知道实际与哪个 Web 服务器进行了交互它只知道与反向代理服务器进行了通信
6.3.3 应用场景
负载均衡反向代理服务器可以根据配置的负载均衡策略将客户端的请求分发到多个后端服务器上以实现负载均衡。这有助于提升网站的整体性能和响应速度特别是在高并发场景下安全保护反向代理服务器可以隐藏后端 Web 服务器的真实 IP 地址降低其被直接攻击的风险。同时它还可以配置防火墙、访问控制列表ACL等安全策略对客户端的请求进行过滤和限制以保护后端服务器的安全缓存加速反向代理服务器可以缓存后端 Web 服务器的响应内容对于重复的请求它可以直接从缓存中返回响应而无需再次向后端服务器发起请求。这可以大大减少后端服务器的负载提升网站的响应速度内容过滤和重写反向代理服务器可以根据配置的规则对客户端的请求进行过滤和重写例如添加或删除请求头、修改请求路径等。这有助于实现一些特定的业务需求如 URL 重写、用户认证等动静分离在大型网站中通常需要将静态资源和动态资源分开处理。通过将静态资源部署在反向代理服务器上可以直接从反向代理服务器返回静态资源的响应而无需再次向后端服务器发起请求。这可以大大提升静态资源的访问速度CDNContent Delivery Network内容分发网络就是采用了反向代理的原理
7.内网穿透 7.1 内网打洞