计算机网络系统
第一章 计网概论
计算机网络定义:两台以上具有独立操作系统的计算机通过某些介质连接成的相互共享软硬件资源的集合体。最重要的功能:连通、共享。 Internet:提供网络应用基础架构,为分布式应用程序提供的通信服务接口。标准文档:RFC。
1.1 协议
协议(Protocol) 是计算机网络中为实现数据交换和通信协同而制定的规则、标准或约定的集合。它规定了通信双方在数据传输过程中的格式、时序、语义和同步方式,确保不同设备或系统间能准确、高效地交互。 功能:控制发送和接收消息。 实例:TCP, IP, HTTP, FTP, SMTP。 协议的三要素: 语法、语义、同步(时序)
1.2 网络边缘
边缘:客户机和服务器。通路:有线或者无线通信链路。
接入网络
将终端系统连接到网络边缘的路由器
1、家庭接入:点对点接入,cable modems 线缆调制解调器,FTTH(Fiber To The Home)-光纤到户 2、企业接入:local area networks (LAN) 3、WiFi 无线接入网络 4、 广域无线接入网络
物理介质
1、双绞线:两根彼此绝缘、相互缠绕成螺旋状的铜线。减少电磁干扰,提高传输质量。 2、同轴电缆和光纤线缆 3、无线电磁波
端系统上的因特网服务
1、面向连接的服务:TCP 服务(HTTP、FTP、SMTP) 2、无连接服务:UDP 服务(流媒体、视频会议、DNS、网络电话)
1.3 网络核心
核心:相互连接的路由器构成的网络。 传输基本原理:
1.3.1 电路交换(Circuit Switching)
在通信过程中,为用户会话预留从源到目的路径上的独占物理资源,形成固定通信链路。
- 资源分配模式
- 独占性:一旦建立连接,路径上的带宽、信道等资源完全分配给该会话,未使用时处于空载状态(不共享)。
- 性能保证:由于资源固定,通信延迟和带宽稳定性高,适合实时业务(如传统电话网络)。
- 分片实现方式
- FDMA(频分多址):将频段划分为多个子频段,每个会话占用固定频段(如早期电话网的频分复用)。
- TDMA(时分多址):将时间划分为时间片,每个会话周期性占用固定时间片(如 GSM 移动通信)。
- 通信流程
- 三阶段:建立连接 → 数据传输 → 释放连接(如电话拨号的过程)。
1.3.2 分组交换(Packet Switching)
将数据分割为离散分组(Packet),通过网络节点转发,共享网络资源。 与电路交换相比,资源利用率高(按需分配),支持大量用户并发,但是无法保证带宽,网络拥塞时延迟波动大。 (一)核心机制
- 分组化传输
- 数据分割:端到端数据流被拆分为多个带头部(含地址信息)的分组。
- 资源共享:分组按需使用链路带宽,不固定占用资源(如互联网数据传输)。
- 转发模式:存储转发(Store-and-Forward)
- 节点处理:每个节点接收完整分组后,检查地址再转发至下一跳。
- 优势:适配不同链路带宽,容错性强(分组可重传),但引入转发延迟。 (二)分组交换类型对比 数据报网络: TCP/IP,分组目的地址决定下一跳,会话期间路由可以改变 虚电路网络: X.25,FR,ATM,每个分组有 1 个标签 (虚电路号,virtual circuit ID), 标签决定下 1 跳。连接建立时确定固定的路径, 并且将保持于整个会话期间。路由器必须为每个连接维护状态信息。
| 类型 | 数据报网络(Datagram) | 虚电路网络(Virtual Circuit) |
|---|---|---|
| 典型案例 | TCP/IP(互联网)、UDP | X.25、FR(帧中继)、ATM(异步传输模式) |
| 路由机制 | 每个分组独立根据目的地址决定下一跳 | 连接建立时确定固定路径,全程保持不变 |
| 状态维护 | 路由器无需维护会话状态,会话期间路由可以变化 | 路由器需为每个连接维护虚电路表(标签映射) |
| 标签标识 | 无标签,依赖 IP 地址 | 分组携带虚电路号(VCID)作为转发依据 |
| (三)资源竞争与拥塞控制 |
- 队列机制:当链路繁忙(拥塞)时,分组进入缓冲区排队,等待转发(可能导致延迟或丢包)。 适应场景:突发数据传输(如网页浏览、文件下载),允许多用户共享网络,但性能受负载影响。 存储转发: 分组每次转发 1 站,在 1 个链路上传输,每经过 1 个链路转发 1 次,转发分组前,要求收到完整分组。适用于对数据完整性要求高的场景(如文件传输、电子邮件),通过校验和重传机制减少错误。但延迟增加。
1.4 ISP 的结构组成
ISP(Internet Service Provider)即互联网服务提供商
1.5 延迟、丢失和吞吐量
延迟的原因:分组在路由器分组缓冲区队列排队, 按序等待 分组延迟的 4 种类型: 1、节点处理时延(检查错误位、选择输出链路) 2、排队时延(等待被发送到输出链路上的时间 ,取决于路由器的拥塞程度) 3、传输时延(发送分组比特流的时间 = 分组长度 L/链路带宽 R) 4、传播时延(传播延迟 = 物理链路长度 d/介质信号传播速度 s) 分组丢失:分组到达输出链路的速率超过输出链路的容量,产生丢失,丢失的分组可能被前路由节点、源节点重传,或不重传。 吞吐量:接收端接收到数据的比特速率 (bps)。吞吐量瓶颈具有短板效应。
1.6 协议层及其服务模型
| 层次 | 核心功能 | 具体职责 | 常见协议/技术 |
|---|---|---|---|
| 应用层 | 直接为用户应用程序提供服务,是用户与网络交互的接口 | 处理特定应用协议(数据格式、交互逻辑) 提供文件传输、电子邮件、网页浏览等服务 | HTTP、HTTPS、FTP、SMTP、POP3、DNS、Telnet |
| 传输层 | 为端到端(进程间)通信提供服务,屏蔽底层网络细节 | 建立/维护/终止逻辑连接(如 TCP 连接) 实现流量控制、差错控制、数据分段重组 通过端口号标识应用进程(如 HTTP 默认 80 端口) | TCP、UDP |
| 网络层 | 负责网络间的数据路由与寻址,实现跨网络通信 | 通过 IP 地址标识设备,完成路由选择 处理分组分片与重组(适应 MTU 限制) 实现异构网络互联(如局域网与广域网) | IP(IPv4/IPv6)、ICMP、ARP、RIP、OSPF |
| 链路层 | 在相邻节点间传输数据,确保物理链路可靠传输 | 将 IP 分组封装为帧(添加 MAC 地址、校验信息) 实现介质访问控制(如 CSMA/CD) 处理差错检测(CRC 校验)和流量控制 | Ethernet(以太网)、PPP、HDLC、802.11(WiFi 链路层) |
| 物理层 | 网络模型最底层,直接与物理介质交互 | 定义物理设备接口标准(电缆类型、引脚功能) 实现比特流传输,处理信号编码/调制 规定传输速率和信号传输方式(单工/全双工) | RJ-45 接口、光纤接口、IEEE 802.3(以太网物理层)、调制解调技术 |
七层模型
- 应用层 → 为计算机用户提供服务
- 表示层 → 数据处理(编解码、加密解密、压缩解压)
- 会话层 → 管理(建立、维护、重连)应用程序之间的会话
- 传输层 → 为两台主机进程之间的通信提供通用的数据传输服务
- 网络层 → 路由和寻址(决定数据在网络的游走路径)
- 数据链路层 → 帧编码和误差纠正控制
- 物理层 → 透明地传送比特流传输

四层模型

第二章 应用层
2.1 应用层协议原理
网络应用程序体系结构
三种:客户机/服务器体系结构,P2P 体系结构,混合
服务器:总是打开的主机,具有固定的、众所周知的 IP 地址,主机群集常被用于创建强大的虚拟服务器
客户机:同服务器端通信,可以间断的同服务器连接,可以拥有动态 IP 地址,客户机相互之间不直接通信
P2P:没有总是打开的服务器,任意一对主机直接相互通信,对等方间歇连接(仅在主动发起请求或提供资源时保持连接)并且可以改变 IP 地址,比如 Gnutella
进程通信:同一主机上的两个进程通过内部进程通信机制进行通信,不同主机上的进程通过交换报文相互通信
进程与计算机网络的接口-套接字
- 套接字是应用层与传输层之间的接口, 发送进程通过套接字将报文“推出”到网络,接收进程通过套接字“接入”报文。套接字屏蔽了底层网络传输细节(如链路传输、路由选择),进程只需关注数据的发送与接收。
- 套接字是操作系统提供的网络编程接口,用户通过 API 可控制:
- 传输协议选择:如 TCP(可靠连接)或 UDP(无连接)。
- 参数配置:如超时时间、缓冲区大小等(不同协议可配置参数不同)。
通信模型与工作机制
1. 进程标识与寻址 网络中唯一标识进程需组合主机 IP 地址+ 端口号(Port Number) 2. 数据传输流程类比
- 发送进程视角:
应用层数据 → 套接字(门户)→ [底层网络设施(如TCP/UDP协议)] → 目标套接字
(推送报文) (假定运输设施存在) (接收报文)
套接字的类型与应用场景
1. 基于传输协议的分类
- 流式套接字(SOCK_STREAM):
- 基于 TCP 协议,提供面向连接的可靠传输(保证顺序、无丢失、无重复)。
- 适用场景:文件传输(FTP)、网页浏览(HTTP)。
- 数据报套接字(SOCK_DGRAM):
- 基于 UDP 协议,提供无连接的不可靠传输(低延迟,不保证可靠性)。
- 适用场景:实时视频(RTSP)、网络语音(VoIP)。 2. 套接字地址结构(Socket Address)
- 在 TCP/IP 中,套接字地址由IP 地址+端口号组成,称为“套接字对”(Socket Pair),例如:
(192.168.1.1:80)。
2.2 Web 应用和 HTTP 协议
使用 TCP: 客户初始化一个与 HTTP 服务器 80 端口的 TCP 连接 (创建套接字),HTTP 服务器接受来自客户的 TCP 连接请求, 建立连接,Browser (HTTP client)和 Web 服务器 (HTTP server) 交换 HTTP 消息(应用层协议消息)包括 HTTP 请求和响应消息,最后结束(或叫关闭)TCP 连接
HTTP 是无状态协议:HTTP 服务器不维护客户先前的状态信息。
HTTP 的发展

定义往返时间 RTT(Round-Trip Time): 1 个小分组从客户主机到服务器再到客户主机所花费的时间 HTTP/1.0 响应时间: total = 2RTT+transmit time 1 个 RTT 用于建立 TCP 连接,1 个 RTT 用于 HTTP 请求/响应消息的交互,html 文件传输时间
HTTP/1.1 是持久连接:一个 TCP 连接上可以传送多个对象
HTTP/2:对象被划分为帧(frame),帧交错传输,减少多对象 HTTP 请求的延迟 ,但仍通过单个 TCP 连接
HTTP/3:通过 UDP 增加了安全性、每个对象的错误和拥塞控制
HTTP 报文格式
请求报文:
响应报文:
#### 访问网页的全过程
[访问网页的全过程(知识串联) | JavaGuide](https://javaguide.cn/cs-basics/network/the-whole-process-of-accessing-web-pages.html)
- 在浏览器中输入指定网页的 URL。
- 浏览器通过 DNS 协议,获取域名对应的 IP 地址。
- 浏览器根据 IP 地址和端口号,向目标服务器发起一个 TCP 连接请求。
- 浏览器在 TCP 连接上,向服务器发送一个 HTTP 请求报文,请求获取网页的内容。
- 服务器收到 HTTP 请求报文后,处理请求,并返回 HTTP 响应报文给浏览器。
- 浏览器收到 HTTP 响应报文后,解析响应体中的 HTML 代码,渲染网页的结构和样式,同时根据 HTML 中的其他资源的 URL(如图片、CSS、JS 等),再次发起 HTTP 请求,获取这些资源的内容,直到网页完全加载显示。
- 浏览器在不需要和服务器通信时,可以主动关闭 TCP 连接,或者等待服务器的关闭请求。
Cookies:跟踪用户
Cookies 是由 Web 服务器存储在用户浏览器中的小型文本文件,用于跟踪用户行为和状态。 工作原理:
- 服务器返回响应时,通过
Set-Cookie头部将 Cookies 存入浏览器。 - 后续浏览器向同一服务器发送请求时,自动携带 Cookies,服务器通过解析 Cookies 识别用户。
如何保存用户状态
Session+Cookie保存状态
- 用户向服务器发送用户名、密码、验证码用于登陆系统。
- 服务器验证通过后,会为这个用户创建一个专属的 Session 对象(可以理解为服务器上的一块内存,存放该用户的状态数据,如购物车、登录信息等)存储起来,并给这个 Session 分配一个唯一的
SessionID。 - 服务器通过 HTTP 响应头中的
Set-Cookie指令,把这个SessionID发送给用户的浏览器。 - 浏览器接收到
SessionID后,会将其以 Cookie 的形式保存在本地。当用户保持登录状态时,每次向该服务器发请求,浏览器都会自动带上这个存有SessionID的 Cookie。 - 服务器收到请求后,从 Cookie 中拿出
SessionID,就能找到之前保存的那个 Session 对象,从而知道这是哪个用户以及他之前的状态了。 使用 Session 的时候需要注意下面几个点: - 客户端 Cookie 支持:依赖 Session 的核心功能要确保用户浏览器开启了 Cookie。
- Session 过期管理:合理设置 Session 的过期时间,平衡安全性和用户体验。
- Session ID 安全:为包含
SessionID的 Cookie 设置HttpOnly标志可以防止客户端脚本(如 JavaScript)窃取,设置 Secure 标志可以保证SessionID只在 HTTPS 连接下传输,增加安全性。 Session 数据本身存储在服务器端。常见的存储方式有: - 服务器内存:实现简单,访问速度快,但服务器重启数据会丢失,且不利于多服务器间的负载均衡。这种方式适合简单且用户量不大的业务场景。
- 数据库 (如 MySQL, PostgreSQL):数据持久化,但读写性能相对较低,一般不会使用这种方式。
- 分布式缓存 (如 Redis):性能高,支持分布式部署,是目前大规模应用中非常主流的方案。
Session+URL 重写 (URL Rewriting)
如果用户的浏览器禁用了 Cookie,或者某些情况下不便使用 Cookie,还有一种备选方案是 URL 重写。这种方式会将 SessionID 直接附加到 URL 的末尾,作为参数传递。例如:http://www.example.com/page?sessionid=xxxxxx。服务器端会解析 URL 中的 sessionid 参数来获取 SessionID,进而找到对应的 Session 数据。
Token-based 认证 (如 JWT - JSON Web Tokens)
尤其适用于前后端分离的架构和微服务。 JWT 基础概念详解 | JavaGuide
Web 缓存(代理服务器)
- 定义:Web 缓存是存储 Web 资源(如网页、图片、视频)的中间服务器(代理服务器),用于减少重复请求的网络延迟。
- 核心作用:
- 提高访问速度:用户请求资源时,若缓存中存在副本,直接返回缓存数据,避免重复从源服务器获取。
- 减轻服务器负载:减少源服务器的请求次数,降低带宽消耗。
条件 GET 方法
- 定义:HTTP 协议中的
GET请求扩展方式,用于判断缓存资源是否需要更新,避免重复传输完整数据。 - 工作原理:
- 浏览器首次请求资源时,服务器返回资源并附带缓存标识(如
Last-Modified时间、ETag哈希值)。 - 后续请求时,浏览器通过
If-Modified-Since或If-None-Match头部携带缓存标识,询问服务器资源是否更新。 - 若资源未更新,服务器返回
304 Not Modified,浏览器使用本地缓存;若更新,则返回新资源(200 OK)。
- 浏览器首次请求资源时,服务器返回资源并附带缓存标识(如
- 优势:减少网络传输量,提升缓存效率,降低带宽消耗。
GET 和 POST 的区别
- 语义(主要区别):GET 通常用于获取或查询资源,而 POST 通常用于创建或修改资源。
- 幂等:GET 请求是幂等的,即多次重复执行不会改变资源的状态,而 POST 请求是不幂等的,即每次执行可能会产生不同的结果或影响资源的状态。
- 格式:GET 请求的参数通常放在 URL 中,形成查询字符串(querystring),而 POST 请求的参数通常放在请求体(body)中,可以有多种编码格式,如 application/x-www-form-urlencoded、multipart/form-data、application/json 等。GET 请求的 URL 长度受到浏览器和服务器的限制,而 POST 请求的 body 大小则没有明确的限制。不过,实际上 GET 请求也可以用 body 传输数据,只是并不推荐这样做,因为这样可能会导致一些兼容性或者语义上的问题。
- 缓存:由于 GET 请求是幂等的,它可以被浏览器或其他中间节点(如代理、网关)缓存起来,以提高性能和效率。而 POST 请求则不适合被缓存,因为它可能有副作用,每次执行可能需要实时的响应。
WebSocket
WebSocket 和 HTTP对比
两者都是基于 TCP 的应用层协议,都可以在网络中传输数据。
- WebSocket 是一种双向实时通信协议,而 HTTP 是一种单向通信协议。并且,HTTP 协议下的通信只能由客户端发起,服务器无法主动通知客户端。
- WebSocket 使用 ws:// 或
wss://(使用 SSL/TLS 加密后的协议,类似于 HTTP 和 HTTPS 的关系) 作为协议前缀,HTTP 使用 http:// 或 https:// 作为协议前缀。 - WebSocket 可以支持扩展,用户可以扩展协议,实现部分自定义的子协议,如支持压缩、加密等。
- WebSocket 通信数据格式比较轻量,用于协议控制的数据包头部相对较小,网络开销小,而 HTTP 通信每次都要携带完整的头部,网络开销较大(HTTP/2.0 使用二进制帧进行数据传输,还支持头部压缩,减少了网络开销)
WebSocket 的工作步骤
- 客户端向服务器发送一个 HTTP 请求,请求头中包含
Upgrade: websocket和Sec-WebSocket-Key等字段,表示要求升级协议为 WebSocket; - 服务器收到这个请求后,会进行升级协议的操作,如果支持 WebSocket,它将回复一个 HTTP 101 状态码,响应头中包含 ,
Connection: Upgrade和Sec-WebSocket-Accept: xxx等字段、表示成功升级到 WebSocket 协议。 - 客户端和服务器之间建立了一个 WebSocket 连接,可以进行双向的数据传输。数据以帧(frames)的形式进行传送,WebSocket 的每条消息可能会被切分成多个数据帧(最小单位)。发送端会将消息切割成多个帧发送给接收端,接收端接收消息帧,并将关联的帧重新组装成完整的消息。
- 客户端或服务器可以主动发送一个关闭帧,表示要断开连接。另一方收到后,也会回复一个关闭帧,然后双方关闭 TCP 连接。 另外,建立 WebSocket 连接之后,通过心跳机制来保持 WebSocket 连接的稳定性和活跃性
2.3 文件传输协议:FTP
核心架构与连接机制
FTP 采用双连接机制(区别于 HTTP 等单连接协议):
- 控制连接(Control Connection)
- 端口:默认使用 TCP 端口 21(始终开启,用于传输命令和响应)。
- 功能:客户端与服务器建立长期连接,传输 FTP 命令(如登录、列表查询、文件操作指令等)。
- 特点:基于文本交互,命令和响应均为 ASCII 格式(如
USER、PASS、LIST、RETR等)。
- 数据连接(Data Connection)
- 端口:由传输模式决定(主动模式或被动模式)。
- 功能:临时建立,仅用于传输文件数据或目录列表,传输完成后关闭。
- 两种模式:
- 主动模式(Active Mode)
- 服务器主动连接客户端的数据端口(默认 TCP 端口 20)。
- 问题:可能被客户端防火墙拦截(需开放服务器到客户端的出站端口)。
- 被动模式(Passive Mode)
- 客户端主动连接服务器的临时端口(服务器通过
PASV命令告知客户端端口号)。 - 优势:适应复杂网络环境(如 NAT、防火墙),现代应用更常用。
- 客户端主动连接服务器的临时端口(服务器通过
- 主动模式(Active Mode)
核心功能与操作流程
- 用户认证
- 支持明文认证(默认):客户端通过
USER和PASS命令发送用户名和密码。 - 可选匿名登录:用户名
anonymous,密码通常为邮箱地址(用于公开文件共享)。
- 支持明文认证(默认):客户端通过
- 文件传输操作
- 下载(Retrieve):客户端发送
RETR命令请求服务器传输文件。 - 上传(Store):客户端发送
STOR命令向服务器写入文件。 - 其他操作:目录浏览(
LIST/NLST)、文件删除(DELE)、重命名(RNFR/RNTO)等。
- 下载(Retrieve):客户端发送
- 传输类型与格式
- 文本模式(ASCII):用于传输文本文件(如
.txt),会自动转换换行符(如 Windows 的 CRLF 与 Unix 的 LF 互转)。 - 二进制模式(Binary):用于传输二进制文件(如
.zip、.exe),按字节原样传输,避免格式错乱。
- 文本模式(ASCII):用于传输文本文件(如
2.4 电子邮件 SMTP,POP3/IMAP
电子邮件系统的三大核心组成部分
- 用户代理 User Agents
-
定义:用户直接交互的软件或客户端,负责邮件的撰写、阅读、管理及与服务器的通信。
-
核心功能:
- 内容操作:支持撰写、编辑、回复、转发邮件,管理联系人列表。
- 存储与检索:将邮件存储在本地或服务器(如草稿箱、收件箱),提供搜索功能。
- 协议交互:通过邮件协议(如 SMTP、POP3、IMAP)与服务器通信,发送/接收邮件。
-
典型示例:Gmail、Outlook.com、网易邮箱。
- 邮件服务器 Mail Servers
- 定义:负责邮件传输、存储和分发的基础设施,是邮件系统的“中转站”。
- 分类及功能:
- 发送方邮件服务器(SMTP 服务器):客户使用 TCP 来可靠传输邮件消息到服务器端口号 25,通过 SMTP 协议将邮件传输至接收方服务器。传输的 3 个阶段:握手 (问候),邮件消息的传输,结束。SMTP 使用持久连接,SMTP 要求邮件消息(header & body)必须是 7-bit ASCII,SMTP 服务器使用 CRLF.CRLF 来判断邮件消息的结束
- 接收方邮件服务器(POP3/IMAP 服务器):存储用户邮件,等待用户代理通过 POP3 或 IMAP 协议下载或同步。
- 关键特性:
- 可靠性:支持邮件队列机制,若传输失败可重试(如延迟发送)。
- 安全性:部署反垃圾邮件过滤、病毒扫描、加密传输(如 TLS)等功能。
- 核心协议 Mail Protocols
| 协议 | 功能 | 传输方向 | 连接方式 | 服务器存储 | 多设备同步 | 场景 | 端口 |
|---|---|---|---|---|---|---|---|
| SMTP | 发送/中转邮件 | 客户端 → 服务器 或 服务器 → 服务器 | TCP | 不存储邮件 | 不涉及 | 发件操作 | 25 |
| POP3 | 下载邮件 | 服务器 → 客户端 | TCP | 下载后默认删除 | 不支持 | 单机离线阅读 | 110 |
| IMAP | 管理/同步邮件 | 客户端 ↔ 服务器 | TCP | 保留服务器副本 | 支持 | 多设备实时协作 | 143 |
电子邮件的工作流程
- 撰写与发送阶段:
- 用户通过 UA 撰写邮件,UA 调用 SMTP 协议连接发送方服务器(如 smtp.163.com),将邮件内容传输至服务器。
- 传输与路由阶段:
- 发送方服务器根据收件人邮箱域名(如@example.com),通过 DNS 查询找到接收方服务器的 MX(邮件交换)记录,建立 SMTP 连接并传输邮件。
- 若接收方服务器不可达,发送方服务器会暂存邮件并定期重试(通常持续数天)。
- 接收与存储阶段:
- 接收方服务器收到邮件后,将其存储在收件人的邮箱账户中,等待 UA 通过 POP3 或 IMAP 协议获取。
- 读取与管理阶段:
- 用户通过 UA 连接接收方服务器,使用 POP3 或 IMAP 协议下载或同步邮件。例如:
- POP3 模式:邮件下载至本地后,服务器默认删除(适合单设备离线使用)。
- IMAP 模式:邮件保留在服务器,支持多设备同步(如网页端与手机端同时查看更新)。
- 用户通过 UA 连接接收方服务器,使用 POP3 或 IMAP 协议下载或同步邮件。例如:
2.5 DNS(域名系统):因特网的目录服务
DNS(Domain Name System,域名系统)是互联网的核心基础设施之一,本质上是一个存储资源记录(RR,Resource Records)的分布式数据库系统,用于将人类易读的域名解析为计算机可识别的 IP 地址。
四个基本功能
1、主机名到 IP 地址的转换。 2、主机别名:一个主机可以有一个规范主机名和多个主机别名 3、邮件服务器别名 4、负载分配:DNS 实现冗余服务器,一个 IP 地址集合可以对应于同一个规范主机名
⭐DNS 工作原理
1. 域名结构与层级 域名采用层次化结构,由右至左分为多个层级:
- 根域名(
.):最高层级,全球仅 13 组根服务器(标识为 A~M)。 - 顶级域名:如
.com、.org、.cn(国家/地区代码顶级域名,如.cn代表中国)。 - 二级域名:如
abc.com中的abc,由用户注册并管理。 - 子域名:如
mail.abc.com中的mail,用于区分同一域名下的不同服务。
2. 解析流程(递归查询与迭代查询)
当用户在浏览器输入域名时,DNS 解析过程如下:
- 客户端查询本地 DNS 缓存:若存在记录,直接返回 IP 地址;否则进入下一步。
- 递归查询本地域名服务器(LDNS):
- LDNS 向根域名服务器询问该域名的顶级域名服务器地址。
- 根服务器返回对应顶级域名服务器(如
.com服务器)的地址。 - LDNS 向顶级域名服务器询问二级域名服务器(如
abc.com服务器)的地址。 - 二级域名服务器返回该域名对应的 IP 地址,LDNS 缓存结果并返回给客户端。
整个过程**通过递归查询(名字解析的负担交给被查询的名字服务器)和迭代查询(问别的服务器)**结合完成,无需用户手动参与。
3. DNS 记录类型
RR 格式: (name, value, type,ttl)
DNS 通过不同类型的记录存储域名相关信息,常见类型包括:
| 记录类型 | 作用 | 示例 |
|---|---|---|
| A | 域名指向 IPv4 地址 | example.com A 192.0.2.1 |
| AAAA | 域名指向 IPv6 地址 | example.com AAAA 2001:db8::1 |
| MX | 指定邮件服务器地址(优先级由数字表示,数字越小优先级越高) | example.com MX 10 mail.example.com |
| CNAME | 别名记录,将一个域名指向另一个域名(常用于 CDN 或服务迁移) | cdn.example.com CNAME example.cloudflare.com |
| NS | 指定域名的权威名称服务器(用于 delegation 机制) | example.com NS ns1.example.com |
| TXT | 存储文本信息(常用于 SPF、DKIM 等邮件安全验证) | example.com TXT "v=spf1 mx -all" |
| 一张图看懂 DNS 域名解析全过程 - 知乎 | ||
![]() |

DNS 报文
DNS 的关键特性与技术
1. 分布式与冗余设计:DNS 系统采用分布式架构,避免单点故障。 2. 缓存机制
- 各级 DNS 服务器和客户端会缓存解析结果,减少重复查询压力,提升访问速度。
- 缓存时间由
TTL(Time To Live)字段控制,单位为秒(如TTL 3600表示缓存 1 小时)。 3. 专用 DNS 服务 - 公共 DNS:如 Google DNS(8.8.8.8)、Cloudflare Warp(1.1.1.1),提供高速、安全的解析服务。
- 私有 DNS:企业内部使用,用于解析私有域名(如
intranet.example),与公网隔离。
DNS 面临的安全威胁
- DNS 欺骗(DNS Spoofing):伪造解析结果,引导用户访问恶意网站。
- DNS 缓存污染:篡改 DNS 服务器的缓存记录,导致错误解析。
- DDoS 攻击:针对 DNS 服务器的分布式拒绝服务攻击,导致服务中断。
- 域名劫持:通过攻击域名注册商或 DNS 服务器,篡改域名指向。
实践 :nslookup
2.6 P2P 技术
P2P 的核心定义与本质
P2P(Peer-to-Peer,点对点技术)是一种去中心化的网络架构,其中每个节点(称为“对等节点”或“Peer”)既作为客户端请求服务,又作为服务器提供服务,无需依赖中心化服务器。其核心特点包括:
- 去中心化:无中心节点,所有 Peer 地位平等,资源分布存储于各节点。
- 自组织性:节点可动态加入或离开网络,自动发现和连接其他节点。
- 高扩展性:网络规模越大,可用资源和带宽越丰富(区别于传统 C/S 架构的服务器瓶颈)。
工作原理与架构分类
1. 经典架构类型
根据节点间协作方式,P2P 可分为三类: (1)集中式 P2P
- 特点:存在目录服务器(如早期的 Napster),用于存储节点索引信息(如文件位置)。
- 优缺点:
- 优点:查询效率高,类似传统 C/S 架构。
- 缺点:目录服务器易成为单点故障,且面临版权监管风险(如 Napster 被关停)。
(2)分布式非结构化 P2P
- 特点:无中心服务器,节点通过洪泛(Flooding)或随机转发发现资源(如 Gnutella、BitTorrent 的 DHT 网络)。
- 关键技术:
- 洪泛查询:节点向相邻节点广播请求,逐步扩散至全网。
- Kademlia(KAD)协议:基于分布式哈希表(DHT)的节点定位算法,用于 BitTorrent 等场景。
(3)分布式结构化 P2P
- 特点:通过**分布式哈希表(DHT, Distributed Hash Table)**结构化组织节点,资源存储位置可通过算法精确计算(如 Chord、CAN、Pastry)。
- 优势:查询复杂度低(通常为对数级),支持大规模动态网络,适合需要高效定位的场景(如区块链、分布式存储)。
2. 核心工作流程(以文件共享为例)
- 节点加入网络:通过引导节点(Bootstrap Node)获取初始连接列表。
- 资源索引与发布:节点将本地文件哈希值、元数据等信息注册到 DHT 网络或目录服务器。
- 资源查询:
- 集中式:向目录服务器请求目标文件的节点列表。
- 分布式:通过 DHT 算法计算目标节点位置,或洪泛查询全网。
- 数据传输:节点直接建立连接,传输文件数据(如 BitTorrent 的分片下载)。
2.7 内容分发网络 CDN
内容分发网络(Content Delivery Network,CDN) 是一种通过在全球各地部署分布式服务器(节点),将内容(如网页、图片、视频、文件等)缓存到离用户更近的位置,从而提高内容传输速度、降低延迟,并提升用户体验的网络架构。
两种部署原则
就近性原则:将内容缓存至离用户物理位置或网络路径最近的节点,降低延迟并提升访问速度 负载均衡原则:优化全网流量分配,避免单个节点过载,确保整体服务稳定性和资源利用率
CDN 的关键组成部分
- 边缘节点(Edge Nodes)
- 分布在全球各地的缓存服务器,直接响应用户请求,存储热门内容的副本。
- 作用:就近提供内容,减少用户到源站的物理距离和传输路径。
- 中心服务器(源站,Origin Server)
- 存储内容的原始版本,当边缘节点无用户所需内容时,边缘节点会向源站请求获取。
- 负载均衡设备(Load Balancing)
- 包括DNS 负载均衡和HTTP 重定向,用于将用户请求分配到最优的边缘节点。
- 策略:根据用户 IP 地址、网络延迟、节点负载等因素,选择“最快”节点响应请求。
- 内容管理系统(CMS)
- 负责将源站内容分发到边缘节点,支持内容更新、缓存刷新等操作。
CDN 的工作原理
- 用户请求流程
- 用户在浏览器输入网址(如
www.example.com),首先通过 DNS 解析获取 CDN 的全局负载均衡节点 IP。 - 负载均衡节点根据用户位置、节点状态等,返回离用户最近的边缘节点 IP。
- 用户向边缘节点发起请求:
- 若边缘节点有缓存内容,直接返回给用户(响应速度极快);
- 若没有,边缘节点向源站请求内容,缓存到本地后再返回给用户,并更新缓存。
- 用户在浏览器输入网址(如
- 内容分发流程
- 主动分发:源站通过 CMS 将内容预先推送到边缘节点(如热门视频上线前预缓存)。
- 被动分发:边缘节点在接收到用户请求时,按需从源站拉取内容并缓存(适用于低频访问内容)。
第三章 传输层
3.1 传输层服务
在两个不同的主机上运行的进程之间提供逻辑通信,是可靠,增强的的网络层服务。传输层协议运行在端系统。
发送方: 将应用程序报文分成数据段传递给网络层。
接受方: 将数据段重新组装成报文传递到应用层。
传输层的两大协议:TCP 与 UDP
传输层的核心功能
- 复用与分用(Multiplexing/Demultiplexing)
- 复用:传输层多个进程的数据可通过同一个传输层协议(如 TCP/UDP)发送到网络层。
- 分用:传输层根据**端口号(Port Number)**将接收的数据准确交付给对应的进程。
- 端口号:
- 16 位无符号整数(范围 0~65535),标识应用进程(如 HTTP 默认端口 80,HTTPS 默认端口 443)。
- 分为知名端口(Well-Known Ports,0~1023)、注册端口(1024~49151)、动态/私有端口(49152~65535)。
- 流量控制(Flow Control)
- 解决发送方与接收方速度不匹配的问题,避免接收方因缓冲区满而丢包。
- TCP 通过滑动窗口协议实现流量控制,UDP 无内置流量控制(需应用层自行处理)。
- 差错控制(Error Control)
- 检测并纠正传输过程中的错误(如数据 corruption、丢包)。
- TCP 通过校验和(Checksum)、序列号、确认应答、重传机制实现可靠传输;UDP 仅通过校验和检测错误,不重传。
- 连接管理(仅 TCP)
- 负责建立、维护和释放端到端的连接,通过三次握手和四次挥手确保连接可靠。
TCP 与 UDP 对比
| 特性 | TCP | UDP |
|---|---|---|
| 连接类型 | 面向连接(需三次握手) | 无连接(直接发送) |
| 可靠性 | 可靠(保证交付、有序、无重复) | 不可靠(尽力而为,不保证交付) |
| 传输单位 | 字节流(无消息边界) | 数据报(保留消息边界) |
| 流量/拥塞控制 | 有(滑动窗口、拥塞控制算法) | 无(需应用层实现) |
| 首部开销 | 较大(20 字节固定首部,可扩展) | 较小(8 字节固定首部) |
| 延迟 | 较高(连接建立/维护开销) | 低(无连接开销) |
| 典型应用 | HTTP、FTP、邮件、远程桌面 | 直播、游戏、DNS、SNMP |
传输层与应用层的交互
端口号的作用:传输层通过端口号将数据分发给对应的应用程序,例如: 1、浏览器访问网页时,客户端随机选择一个动态端口(如 50001),服务器通过 80(HTTP)或 443(HTTPS)端口响应。 2、 DNS 客户端通过 UDP 53 端口发送查询请求,服务器通过 UDP 53 端口返回结果。
传输层的发展与扩展
- QUIC 协议(Quick UDP Internet Connections)
- 基于 UDP 的新型传输层协议,由 Google 开发,旨在替代 TCP。
- 特点:低延迟(减少握手次数)、多路复用、加密传输(内置 TLS)、连接迁移(切换网络时保持连接)。
- 应用:HTTP/3 协议基于 QUIC,已被主流浏览器支持。
- SCTP 协议(Stream Control Transmission Protocol)
- 面向连接的可靠传输协议,支持多流(Multi-Stream)和多宿主(Multi-Homing)。
- 应用:实时通信(如 VoIP)、电信网络中的信令传输。
3.2 多路复用与多路分解
基本概念与核心作用
多路复用(Multiplexing)和多路分解(Demultiplexing)是计算机网络中实现资源共享与精准分发的关键机制,主要解决以下问题:
- 多路复用:在发送端将多个应用进程的数据合并到一条传输通道(如一条物理链路或一个传输层连接)中传输,提高资源利用率。
- 多路分解:在接收端将混合的数据按规则分离,准确交付给对应的应用进程。
核心作用: 在传输层(TCP/IP 模型)中,这两个机制是实现“端到端通信”的基础,依赖**端口号(Port)**完成进程级的标识与分发。
- 在传输层(如 TCP/UDP)中,通过端口号(Port Number)实现应用进程的标识与区分;
- 在网络层、数据链路层等更低层中,通过类似机制实现不同协议或设备的数据复用与分解。
多路复用(传输层发送端)
原理:
- 同一主机上的多个应用进程(如浏览器、邮件客户端、即时通信工具)可同时通过同一个传输层协议(TCP 或 UDP)发送数据。
- 传输层将各进程的数据封装成独立的报文段(Segment/UDP 数据报),并在报头中添加源端口号(标识发送进程)和目标端口号(标识接收进程)。
- 所有报文段通过网络层的同一 IP 地址发送到网络中,共享底层网络资源(如带宽)。 示例:
- 客户端同时用浏览器(进程 A,端口 50001)访问网页(服务器 80 端口)和用 QQ(进程 B,端口 50002)聊天:
- 进程 A 的数据 → 封装为 TCP 报文段,源端口 50001,目标端口 80;
- 进程 B 的数据 → 封装为 UDP 数据报,源端口 50002,目标端口 QQ 服务器端口(如 8000);
- 两者通过同一 IP 地址发送,共享网络层的 IP 协议。
多路分解(传输层接收端)
原理:
主机收到 IP 数据报:每个数据报有源 IP 地址,目的 IP 地址,每个数据报搬运一个数据段,每个数据段有源和目的端口号 。 主机用 IP 地址和端口号指明数据段属于哪个合适的套接字。
- TCP 的多路复用/分解:
- 每个 TCP 套接字由四元组唯一标识:(源 IP 地址,源端口号,目标 IP 地址,目标端口号)。
- 例:同一服务器可通过不同目标端口号同时处理多个客户端的 HTTP 请求(如客户端 A 连接 80 端口,客户端 B 连接 80 端口,但源 IP 和源端口不同)。
- UDP 的多路复用/分解:
- UDP 套接字由两个因素指定:(目的 IP 地址, 目的端口号),当主机收到 UDP 数据段:检查数据段中的目的端口号,用端口号指示 UDP 数据段属于哪个套接字。具有不同的源 IP 地址且/或源端口号,但具有相同的目的 IP 地址和目的端口号的 IP 数据报,指向同样的套接字
与其他层的多路复用/分解对比
| 层次 | 复用/分解对象 | 标识机制 | 典型场景 |
|---|---|---|---|
| 传输层 | 应用进程的数据 | 端口号(Port) | 浏览器与邮件客户端共享网络连接 |
| 网络层 | 不同协议的数据包 | 协议号(Protocol Number,如 IP 报头) | IP 网络中同时传输 TCP、UDP、ICMP 数据 |
| 数据链路层 | 不同网络层协议的数据帧 | 类型字段(Type Field,如 Ethernet) | 以太网中同时传输 IP、ARP、RARP 数据帧 |
| 物理层 | 不同信号或信道 | 频率、时间片、编码等 | 频分复用(FDM)、时分复用(TDM) |
常见问题与解决方案
- 端口冲突: 同一主机上的两个应用进程不能同时绑定同一个端口号。
- 解决方案:
- 服务器端:使用知名端口(需权限)或注册端口(避免冲突);
- 客户端:动态分配端口(操作系统自动管理,确保唯一性)。
- 解决方案:
- NAT(网络地址转换)中的端口复用:
- 家庭路由器通过 NAT 将多个设备的私有 IP 转换为同一公网 IP 时,通过端口号区分不同设备的连接(即 NAPT,网络地址端口转换)。 例如:设备 A(私有 IP 192.168.1.2,端口 50001)和设备 B(192.168.1.3,端口 50001)访问同一服务器时,路由器通过公网 IP+不同端口号(如 12345 和 12346)区分流量。
3.3 无连接传输:UDP
用户数据报协议(UDP,User Datagram Protocol) 特点:无连接、不可靠传输、基于数据报。UDP 只在 IP 的数据报服务之上增加了端口的功能和差错检测的功能。 应用场景:对实时性要求高、允许少量丢包的场景,如音视频直播(RTMP/RTSP)、视频会议(WebRTC)、在线游戏(FPS/MMO)、DNS 查询、SNMP(网络管理)等。 核心机制:
- 无连接:发送数据前无需建立连接,直接封装数据报发送,延迟低。
- 不可靠传输:不保证数据到达、不保证顺序、不处理重复包,仅提供“尽力而为”的交付。
- 基于数据报:保留应用层的消息边界,发送方的每个 UDP 数据报对应接收方的一个消息。 •UDP 是面向报文的。发送方 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。 •应用层交给 UDP 多长的报文,UDP 就照样发送,即一次发送一个报文。 •接收方 UDP 对 IP 层交上来的 UDP 用户数据报,在去除首部后就原封不动地交付上层的应用进程,一次交付一个完整的报文。
•应用程序必须选择合适大小的报文。
UDP 首部
UDP 首部有 8 个字节,由 4 个字段构成,每个字段都是两个字节:
1.源端口: 源端口号,需要对方回信时选用,不需要时全部置 0.
2.目的端口:目的端口号,在终点交付报文的时候需要用到。
3.长度:UDP 的数据报的长度(包括首部和数据)其最小值为 8(只有首部)
4.校验和:检测 UDP 数据报在传输中是否有错,有错则丢弃。
UPD 检验:在计算检验和时,临时把“伪首部”和 UDP 用户数据报连接在一起。伪首部仅仅是为了计算检验和。
3.4 可靠数据传输原理
rdt 协议
rdt(Reliable Data Transfer,可靠数据传输)协议是计算机网络中用于实现可靠数据传输的一系列理论模型和协议框架,其核心目标是在不可靠的底层网络上为上层提供可靠的数据传输服务。
- rdt1.0:适用于完美可靠信道,无 bit 错误和分组丢失。发送方将数据封装后发送到下层信道,接收方从下层信道接收数据并提取交付,采用分离的有限状态机(FSM)。
- rdt2.0:针对信道可能出现的 bit 错误,增加了校验和用于差错检测,接收方通过确认(ACKs)和否认(NAKs)反馈分组接收情况,发送方根据反馈重发分组。
- rdt2.1:解决 rdt2.0 中 ACK/NAK 混淆问题,发送方给分组加序号(0 和 1),接收方检查重复分组。发送方需检查 ACK/NAK 是否混淆,状态加倍;接收方要检查重复分组,且不知上一个 ACK/NAK 是否被正确接收。
- rdt2.2:与 rdt2.1 功能相同,但只用 ACKs。接收方在 ACK 中明确被确认报文序号,发送方收到重复 ACK 按 NAK 处理,即重发当前报文。
- rdt3.0:考虑下层信道报文丢失问题,发送方等待 “合理的” 确认时间,超时重发。接收方指定确认报文序号,需倒计时定时器,利用序号处理重复问题。如在 1 Gbps 链路、15 ms 端到端传输延迟、8000bit 报文的情况下,网络利用率较低,为 0.00027 。
⭐流水线技术
1. 核心定义 允许发送方在未收到前一个报文确认(ACK)时,连续发送多个报文,形成“流水线”式传输,显著提升信道利用率。 2. 技术背景与优势
- 对比停止等待协议:发送方每发一个报文必须等待 ACK,信道空闲时间长(如卫星通信中往返延迟达数百毫秒)。 流水线技术:将等待时间用于发送新数据。 发送方允许发送多个未确认报文,提高利用率。有 Go - Back - N 和选择性重传两种形式。Go - Back - N 发送方用 k 位序号,有发送窗口,接收方为正确接收的最高序号分组发 ACK,丢弃失序分组;选择性重传接收方分别确认收到的分组,缓冲失序报文,发送方只重发未确认分组。
滑动窗口协议
滑动窗口协议是流水线技术的基础实现。流水线技术允许发送方在未收到确认时连续发送多个分组(即“流水线”),而滑动窗口协议通过窗口大小限制流水线的长度,避免无节制发送导致的问题。
- 核心思想: 发送方和接收方各自维护一个“窗口”,用于标识允许发送或接收的数据范围。窗口大小表示在无需等待确认的情况下,可发送或接收的最大数据量,以此控制数据传输速率,避免网络拥塞或接收方缓冲区溢出。
- 主要功能:
- 流量控制:根据接收方处理能力动态调整发送速率,防止数据“淹没”接收方。
- 可靠传输:通过序号、确认机制和重传策略,确保数据无丢失、无重复、按序到达。
1. 发送方窗口
- 结构:窗口内包含三类数据分组(以序号从小到大排列):
- 已发送并确认:已收到 ACK,可从窗口移除。
- 已发送未确认:等待接收方确认,若超时未确认则重传。
- 未发送但允许发送:窗口内未发送的分组,可直接发送。
- 滑动机制:当收到接收方对窗口内最小序号分组的确认时,窗口整体向前滑动,允许发送新的分组。
2. 接收方窗口
- 结构:窗口内标识允许接收的分组序号范围,仅接收序号在窗口内的分组,其他分组(如重复或失序)会被丢弃或缓存(取决于协议类型)。
- 滑动机制:当接收方成功接收窗口内最小序号的分组后,窗口向前滑动,通知发送方新的可发送范围(通常通过 ACK 报文携带窗口大小信息)。
Go-Back-N
发送方维护发送窗口,接收方仅确认最高序号正确分组,失序分组直接丢弃。
工作流程示例
- 发送方发送分组 1-5,窗口覆盖 1-5。
- 分组 3 在传输中丢失,接收方收到 1、2、4、5 后,仅对 2 发 ACK(期望接收 3)。
- 发送方收到 ACK 2,但未收到 ACK 3,超时后重传 3~5。
选择性重传
接收方单独确认每个正确分组,缓存失序分组,发送方仅重传未确认分组。 核心优化
- 接收方改进:
- 对每个正确分组单独发 ACK(如 ACK 3、ACK 5),并缓存失序分组(如收到 5 后,若 4 未到则缓存 5)。
- 当连续收到失序分组时,不立即丢弃,等待缺失分组补全后按序交付。
- 发送方改进:
- 仅重传未收到 ACK 的分组(而非全部后续分组),需维护“已发送未确认”分组的状态表。 工作流程示例
- 发送方发送分组 1-5,窗口覆盖 1-5。
- 分组 3 丢失,接收方收到 1、2、4、5,分别发 ACK 1、ACK 2、ACK 4、ACK 5,并缓存 4、5。
- 发送方收到 ACK 1、2、4、5,仅重传未确认的 3。
- 接收方收到 3 后,将 3 与缓存的 4、5 按序交付。
3.5 面向连接传输:TCP
传输控制协议,可靠按序递交(TCP,Transmission Control Protocol) 特点:面向连接、可靠传输、基于字节流。不提供延迟保证和带宽保证。
报文段结构
TCP 序号和确认
序号:数据段中第一个字节在数据流中的位置编号。确认:期望从另外一边收到的下一个字节的序号。 问: 接收方如何处理失序的数据段 答: TCP 规范没有明确规定, 由编程人员处理。
可靠数据传输机制
TCP 发送方通过 “序号 + 确认 + 滑动窗口 + 重传机制” 实现可靠传输 TCP 发送方(简化):实现了 TCP 协议的滑动窗口机制核心逻辑,维护了两个关键变量: NextSeqNum:指向下一个待发送段的序列号 SendBase:指向最早未被确认段的序列号(发送窗口的左边界)
NextSeqNum = InitialSeqNum # 初始化下一个要发送的序列号,用于标识新生成的TCP段
SendBase = InitialSeqNum # 初始化发送窗口的基序号,即最早未被确认的段的序列号
loop (forever) { # 主循环,持续监听事件
switch(event) # 根据不同事件类型执行相应操作
event: data received from application above # 上层应用有数据需要发送
create TCP segment with sequence number NextSeqNum # 创建TCP段,使用NextSeqNum作为序列号
if (timer currently not running) # 如果当前没有运行的定时器
start timer # 启动定时器,用于超时重传机制
pass segment to IP # 将TCP段传递给IP层进行网络传输
NextSeqNum = NextSeqNum + length(data) # 更新NextSeqNum,增加刚刚发送的数据长度
event: timer timeout # 定时器超时事件(说明可能有段丢失)
retransmit not-yet-acknowledged segment with smallest sequence number # 重传序列号最小的未确认段(即SendBase对应的段)
start timer # 重启定时器,继续等待确认
event: ACK received, with ACK field value of y # 收到ACK确认,确认号为y
if (y > SendBase) { # 如果确认号大于当前发送窗口基序号(说明有新的段被确认)
SendBase = y # 更新发送窗口基序号到y,滑动窗口
if (there are currently not-yet-acknowledged segments) # 如果仍有未确认的段
start timer # 重启定时器,等待剩余段的确认
}
} /* end of loop forever */
TCP 发送方核心事件机制
1. 从应用程序接收数据
-
序号分配逻辑:
- 生成 TCP 报文段时,序号字段赋值为该报文段首个数据字节在整个字节流中的位置(如初始序号 ISN=1000,数据长度 100 字节,则序号为 1000,下一段为 1100)。
- 示例:若字节流为
ABCDEFG(7 字节),第一个报文段含ABC(3 字节),则序号为 0(假设 ISN=0),下一段序号为 3。
-
定时器启动条件:
- 若当前没有运行的定时器(即最早未确认的报文段未被计时),则启动定时器,计时对象为最早未确认的报文段(SendBase 对应的段)。
-
超时间隔(TimeOutInterval)设置:
-
基于往返时间(RTT) 动态调整: 初始值通常设为默认值(如 1 秒),后续根据实际测量的 RTT 样本计算平滑往返时间(SRTT) 和偏差(RTT Deviation),公式如下:
SRTT = α × SRTT + (1-α) × RTT样本 (α通常为0.8~0.9)
TimeOutInterval = SRTT + 4 × RTT Deviation
-
2. 超时事件处理
- 重传策略: 重传导致超时的报文段(即序号=SendBase 的段,最早未被确认的段)。
- 示例:发送窗口为[1000, 2000],SendBase=1000,若 1000 号段超时,重传该段,而非窗口内所有段。
- 定时器管理: 重传后重启定时器,且超时间隔可能按指数退避策略增加(如超时一次后 TimeOutInterval 翻倍),避免网络拥塞时频繁重传。 3. 收到确认(ACK)事件处理
- 确认号(ACK Number)的作用: ACK 号表示接收方期望接收的下一个字节序号,隐含前序字节已正确接收(如 ACK=1000 表示 0~999 字节已确认)。
- 窗口滑动逻辑:
- 若 ACK 号 > SendBase(即确认落在发送窗口内):
- 更新 SendBase 为 ACK 号,滑动发送窗口(如原 SendBase=1000,ACK=1500,则窗口左边界右移至 1500)。
- 若仍有未确认的报文段(SendBase < NextSeqNum),则重启定时器,继续计时新的最早未确认段。
- 若 ACK 号 > SendBase(即确认落在发送窗口内):
- 累积确认特性: TCP 支持累积确认,即 ACK=Y 表示 Y 之前的所有字节均已确认(如发送 1000、1500、2000 号段,若 1500 丢失,接收方收到 2000 后仍发 ACK=1000,直到 1500 被重传并确认)。
快速重传机制(Fast Retransmit)
1. 核心原理:通过重复 ACK 检测丢包,提前重传而非等待超时
- 重复 ACK 的产生场景:
- 当报文段 n 丢失时,后续报文段 n+1、n+2 等到达接收方后,接收方因发现序号不连续,会持续发送对 n-1 号段的 ACK(即重复 ACK)。
- 示例:发送段 1、2、3,段 2 丢失,接收方收到 1 后发 ACK=2,收到 3 时发现失序,再次发 ACK=2(重复 ACK),收到 4 时仍发 ACK=2,形成多次重复 ACK。
- 触发条件:发送方收到3 个重复 ACK(即同一 ACK 号连续出现 3 次),判定对应报文段丢失。
2. 快速重传流程
- 检测丢包:收到 3 个重复 ACK(如 ACK=1000 出现 3 次),确认 1000 号段丢失。
- 立即重传:无需等待定时器超时,直接重传丢失的 1000 号段。
- 重启定时器:重传后启动定时器,计时新的最早未确认段。
- 优化措施:重传时可能调整拥塞窗口(cwnd)(如 TCP Reno 算法中,快速重传后执行“拥塞避免”策略)。
3. 快速重传 vs 超时重传
| 维度 | 快速重传 | 超时重传 |
|---|---|---|
| 触发条件 | 3 个重复 ACK | 定时器超时 |
| 延迟性 | 提前重传,减少平均延迟(约 1~2RTT) | 需等待超时(可能数十秒) |
| 网络影响 | 更高效,避免超时重传的带宽浪费 | 超时后可能伴随指数退避,影响效率 |
| 适用场景 | 高带宽网络中快速恢复丢包 | 作为快速重传失败后的兜底机制 |
发送方关键变量与窗口模型
-
发送方三大核心变量:
- SendBase:发送窗口左边界,最早未确认的字节序号。
- NextSeqNum:下一个待发送的字节序号(发送窗口右边界)。
- CongestionWindow(cwnd):拥塞窗口大小,用于限制 “发送方在未收到确认前可发送的数据量”(与滑动窗口共同决定实际发送窗口,取其中最小值)。
-
发送窗口动态变化示例:
初始:SendBase=1000,NextSeqNum=1500(窗口大小500)
发送段1000~1499,收到ACK=1200 → SendBase=1200,窗口滑动至[1200, 1700]
若此时收到3个重复ACK=1200 → 快速重传1200号段,SendBase保持1200,直到收到正确ACK
| 接收方的事件 | TCP 接收方行为 |
|---|---|
| 期望序号的报文段按序到达. 所有在期望序号以前的报文段都被确认 | 延迟 ACK. 等到 500ms 看是否有下一个报文段,如果没有,发送 ACK |
| 期望序号的报文段按序到达另一个按序报文段等待发送 ACK | 立即发送单个累积 ACK, 确认两个有序的报文段 |
| 收到一个失序的报文段,高于期望的序号,检测到缝隙 | 立即发送重复 ACK, 指出期望的序号 |
| 到达的报文段部分地或者完全地填充接收数据间隔 | 立即发送 ACK, 证实缝隙低端的报文段已经收到 |
流量控制
流量控制使用接收窗口:接收缓冲区的剩余空间,接收方在报文段中宣告接收窗口的剩余空间,发送方限制没有确认的数据不超过接收窗口。
连接管理
建立连接,三次握手
TCP 在交换数据报文段之前在发送方和接收方之间建立连接:初始化 TCP 变量(序号,缓冲区流控信息)
Step 1: 客户发送 TCP SYN 报文段到服务器,指定初始的序号,没有数据
Step 2: 服务器接收 SYN, 回复 SYN/ACK 报文段,服务器分配缓冲区,指定服务器的初始序号
Step 3: 客户接收 SYN/ACK, 回复 ACK 报文段, 可能包含数据
关闭连接,四次挥手
客户关闭套接字:clientSocket.close
Step 1: 客户发送 TCP FIN 控制报文段到服务器
Step 2: 服务器接收 FIN, 回复 ACK,进入半关闭连接状态;
Step 3: 服务器发送 FIN 到客户,客户接收 FIN,回复 ACK,进入 “time wait”状态等待结束时释放连接资源
Step 4: 服务器接收 ACK,连接关闭。
#### TCP为什么是三次握手
**为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。如果更多次握手则是浪费时间。**
#### TCP 释放连接时为什么 time_wait 状态必须等待 2MSL 时间
**MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。** RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。
第一,为了保证A发送的最后一个ACK报文能够到达B。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认。B会超时重传这个FIN+ACK报文段,而A就能在2MSL时间内收到这个重传的FIN+ACK报文段。如果A在TIME-WAIT状态不等待一段时间,而是在发送完ACK报文段后就立即释放连接,就无法收到B重传的FIN+ACK报文段,因而也不会再发送一次确认报文段。这样,B就无法按照正常的步骤进入CLOSED状态。
第二,A在发送完ACK报文段后,再经过2MSL时间,就可以使本连接持续的时间所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求的报文段。
冷知识:TCP 协议的操作可以使用一个具有 **11 种状态的有限状态机**来表示
3.6 拥塞控制原理
拥塞是指源主机发送过多的数据导致网络来不及处理,表现:丢失分组 (路由器的缓冲区溢出),长延迟 (在路由器的缓冲区排队)
拥塞的原因与代价
(一)场景 1:两个发送者、两个接收者、一个无限缓冲区路由器、不执行重发、链路带宽为 C
- 假设每个主机最大可达吞吐量为 C/2,总的吞吐量为 C。 结果:当吞吐量达到 C/2 时,拥塞时延变得无限大。
无限缓冲区不能解决拥塞问题,仅能避免丢包,但无法控制时延。
吞吐量与时延的矛盾:当网络负载接近链路带宽时,时延会指数级增长。(排队论中的 M/M/1 队列模型 )
(二)场景 2:一个有限缓冲区路由器、发送方重发丢失的报文
- 情况分析
- 总是重发:会增加额外的工作量。
- 仅当数据丢失时重发:相对合理,但仍有重发开销。
- 超时而没有丢失的报文重发:会导致同样的吞吐量需要比完美情况更大的带宽。
- 代价
- 无效工作量:重发本质是 “补传” 丢包,但丢包已消耗一次传输资源,重发相当于重复劳动。
- 带宽浪费:冗余分组占用链路带宽,例如原本 100KB 数据因重发变成 150KB,链路效率降低 33%。
(三)场景 3:四个发送方、多跳路径、超时/重发
- 代价:当分组丢失后,任何上游路由器的发送能力都浪费了。
拥塞控制
(一)端到端拥塞控制
- 特点:没有从网络中得到明确的反馈,而是从端系统观察到的丢失和延迟推断出拥塞。
- 应用:TCP 采用的方法。
(二)网络辅助的拥塞控制
- 特点:路由器给端系统提供反馈。
- 反馈方式 单 bit 指示拥塞:如 SNA、DECnet、TCP/IP ECN、ATM 等。指明发送者应该发送的速率。
(三)ABR(可用比特率)选学
- 性质:属于“弹性服务”。
- 工作原理
- 如果发送方通道“低载”,发送方应该利用有效带宽。
- 如果发送方通道拥塞,发送方应该调节到保证速率。
3.7 TCP 拥塞控制
TCP 拥塞控制概述
(一)核心机制
- 端到端控制:不依赖网络层反馈,通过**发送方动态调整拥塞窗口(CongWin)**实现。
- 发送速率限制:发送窗口大小 = min(CongWin, RcvWindow),其中 RcvWindow 由接收方通告,CongWin 由网络拥塞状态决定。
- 拥塞感知:通过丢包事件(超时或 3 个重复 ACK)判断拥塞。
(二)关键公式
TCP 经典拥塞控制
(一)慢启动(Slow Start)
当连接开始的时候以指数方式增加速率,初始速率慢但是呈指数快速增长,直到某个阈值或丢失。
- 初始状态:连接建立时,CongWin = 1 MSS(最大段大小)。
- 增长策略:每收到一个 ACK,CongWin 加 1;每经过一个 RTT,CongWin 翻倍(指数增长)。
- 终止条件:达到**ssthresh(慢启动阈值)**或发生丢包事件。
(二)AIMD(加性增乘性减)
发送方增加传输速率(窗口大小),探测可用带宽,直到发生丢包事件
- 加性递增(Additive Increase):每个 RTT 内如果没有丢失事件发生,拥塞窗口增加一个 MSS。
- 乘性递减(Multiplicative Decrease):发生丢包事件后将拥塞窗口减半。
- 效果:形成锯齿状窗口变化,在探测带宽和避免拥塞间平衡。
(三)对拥塞事件的反应
- 超时(Timeout)
- 处理方式:CongWin 立即设置为 1 个 MSS; 窗口开始指数增长(进入慢启动);到达一个阈值后再线性增长
- 意义:超时被视为严重拥塞,强制降低发送速率。
- 收到三个重复 ACK
- 处理方式(TCP Reno):CongWin 减半+3 (Reno 版);然后,窗口线性增长,直接进入拥塞避免阶段
- 逻辑:3 个重复 ACK 表明部分分组已到达,网络仍有传输能力,无需完全重置窗口。
- TCP Tahoe 与 Reno 对比。Tahoe 是比 Reno 更新的版本
| 版本 | 超时处理 | 3 重复 ACK 处理 |
|---|---|---|
| Tahoe | CongWin 置为 1 MSS | 同超时处理 |
| Reno | 同 Tahoe | 快速恢复(不重置窗口) |
TCP 拥塞控制 FSM 图
(一)状态机核心逻辑
- 慢启动阶段:CongWin < ssthresh 时,指数增长。
- 拥塞避免阶段:CongWin ≥ ssthresh 时,线性增长(每 RTT 加 1 MSS)。
- 快速恢复阶段(Reno):收到 3 重复 ACK 后,先调整窗口再线性增长。
(二)阈值动态调整
- 每次丢包后,ssthresh 设为丢包前 CongWin 的一半,最小值为 2 MSS。
TCP 拥塞控制优化版本
(一)TCP CUBIC
-
核心思想:用立方(cube)函数调整窗口,在丢包后更快逼近最优带宽。
-
数学模型:
-
窗口增长公式:
:到达的时间点,为常数。
-
-
优势:离越远增长越快,越近越慢,适合长肥管道网络。
-
应用:Linux 默认拥塞控制算法,广泛用于 Web 服务器。
(二)明确拥塞通告(ECN)
-
网络辅助机制:路由器通过 IP 报头 ToS 字段标记拥塞(ECN=10 或 11)。
接收方在 ACK 中设置 ECE 位通知发送方,包括 IP(IP 头 ECN 位标记)和 TCP(TCP 头 C、E 位标记)。
-
优势:在丢包前预警,减少重发开销。
(三)基于时延的拥塞控制
TCP(传统的 Tahoe/Reno, CUBIC)提高 TCP 的发送速率,直到某些路由器的输出出现数据包丢失——此路由器即为瓶颈链路
- TCP Vegas:目标:维持端到端管道“刚好填满”,避免队列积压。机制:通过监测 RTT 变化调整速率,而非依赖丢包。
- BBR:开发者:Google,部署于骨干网络。核心:同时测量瓶颈带宽和最小 RTT,动态调整发送速率。
- 其他算法:TIMELY、复合 TCP(CTCP)、FAST 等。
第四章 网络层
4.1 概述
网络层功能
-
功能:从发送方主机传输报文段到接收方主机,发送方主机封装报文段(segments)为数据报(datagrams)。接收方主机递交报文段给传输层在每个主机、路由器上都需要运行网络层协议。路由器会检查通过它的所有 IP 数据报的头部字段,然后根据目的 IP 地址对数据报进行转发。
-
如今的因特网网络层不执行连接建立
-
两个主要功能:路由与转发
路由是确定分组从发送方到接收方所经路径的过程;转发是将分组从路由器的输入端口转移到正确输出端口的操作。
路由算法确定端到端路径,转发表确定本地转发。
网络层组成
- 数据平面:本地的,每个路由器自身的功能决定抵达路由器输入端口的数据包如何转发到输出端口。两种数据平面的实现方式: 1.传统的路由算法: 在路由器内实现;2.软件定义网络(software-defined networking, SDN): 在远程服务器上实现
- 控制平面:整个网络范围,决定数据报在端到端路径上的路由器之间如何路由。传统方式下每个路由器有单独路由算法组件,通过交互实现控制;SDN 方法中,由分离的远程控制器和路由器本地控制代理交互实现控制。
网络层服务模型
- 因特网服务:提供尽力而为服务,分组定时、接收顺序和交付都无法保证。
- 可能服务:包括确保交付、具有时延上界的确保交付、有序分组交付、确保最小带宽和确保最大时延抖动等。
4.2 虚电路和数据报网络
连接服务对比:数据报网络提供无连接服务,类似 UDP; 虚电路网络提供连接服务,类似 TCP,网络层的面向连接服务在端系统及网络核心的路由器中实现,传输层则在网络边缘的端系统中实现。 任何网络中的网络层只提供两种服务之一,不会同时提供。
虚电路网络
源于电话网络,网络功能复杂,端系统设备简单。
- 虚电路网络特点:数据传输前需建立连接,分组携带 VC 标识符,路由器维护连接状态,可分配资源。
数据报网络
数据报网络源于互连计算机网络,网络层服务模型简单,端系统功能复杂。高层实现许多功能。
- 数据报网络特点:无呼叫过程,路由器不维护连接状态,使用目的主机地址转发分组,转发表采用地址范围建立表项,通过最长前缀匹配查找输出端口。
路由器查表转发
路由器转发表只维持转发状态信息;转发表由选路算法修改(1 ~ 5 分钟更新);虚电路网络转发表随虚电路的建立和拆除更新。一个端系统发送给另一个端系统的一批分组可能在网络中选择不同的路径,到达的顺序可能不一致。
4.3 路由器的工作原理
路由器结构
很重要的图!!
核心功能是运行路由算法和转发分组,由交换结构、输入端口、输出端口和选路处理器组成。
输入端口功能
包含线路端接、数据链路处理和查找转发模块,实现分组接收、链路层功能和查找转发,可能出现排队和线头阻塞。 
查找与转发
定义:确定到达分组通过交换结构转发至哪个输出端口,通过输入端口内存中的转发表实现。
分布式交换机制
选路处理器计算转发表,给每个输入端口存放一份转发表拷贝。在每个输入端口本地做出交换决策,无须激活中央选路处理器。避免在路由器中某个单点产生转发处理瓶颈。目的:以线速完成输入端口的处理
排队
交换结构
经内存交换受总线带宽限制;经总线交换每次仅一个分组传输,受总线速率限制;经交换矩阵交换可同时传输多个分组,速率较高。
内存交换
输入端口与输出端口之间的交换由 CPU(选路处理器)控制完成;
当分组到达输入端口时,通过中断向选路处理器发出信号,将分组拷贝到处理器内存中; 选路处理器根据分组中的目的地址查表找出适当的输出端口,将该分组拷贝到输出端口的缓存中。
交换速度受总线带宽的速度限制 (每个分组穿过两次总线)
若总线带宽为每秒写入或读出 B 个分组,则总的转发吞吐量 (分组从输入端口被传送到输出端口的总速率)小于 B/2。
总线交换
输入端口通过一条共享总线将分组直接传送到输出端口,不需要选路处理器的干预。
每次只能有一个分组通过总线传送。分组到达一个输入端口时,若总线正忙,会被暂时阻塞,在输入端口排队。 路由器交换带宽受总线速率限制。
交换矩阵交换
纵横式交换机:由 2n 条总线组成,n 个输入端口与 n 个输出端口连接。 到达输入端口的分组沿水平总线穿行,直至与所希望的输出端口的垂直总线交叉点: 若该条垂直总线空闲,则分组被传送到输出端口;否则,该到达的分组被阻塞,必须在输入端口排队
输出端口功能
取出存放在输出端口内存中的分组,并将其传输到输出链路上。 当交换结构将分组交付给输出端口的速率超过输出链路速率,就需要排队与缓存管理功能。当输出端口的缓冲区溢出时,就会出现延时和丢包。
如何管理缓存中的数据包?——包调度(packet scheduling)
FCFS(FIFO,先来先服务);基于优先级的调度;Round Robin(轮询);加权公平排队(Weighted Fair Queuing , WFQ)
4.4 网际协议(IP)☆
IP 数据报格式与分片重组
- 数据报基本结构
- 固定首部:20 字节,包含版本号(ver,4 位,如 IPv4 为 4)、首部长度(IHL,4 位,以 4 字节为单位,最小 5 即 20 字节)、服务类型(TOS,8 位)、总长度(16 位,含首部和数据)、标识符(16 位,分片标识)、标志(3 位,DF 禁止分片,MF 后续分片)、段偏移(13 位,分片在原数据报中的位置,单位 8 字节)、寿命(TTL,8 位,最大跳数)、首部检查和(16 位,仅校验首部)、源/目的 IP 地址(各 32 位)。
- 数据部分:可变长,通常承载 TCP/UDP 段,最大长度受 MTU 限制。MTU 指数据链路层允许传输的单个数据帧的最大字节数
- 分片与重组机制
- 原因:不同数据链路 MTU 不同(如以太网 MTU 为 1500 字节),大分组需分割。
- 分片标识:同一数据报分片共享相同标识符,通过段偏移(offset)和标志位(MF=1 表示非最后分片,DF=1 禁止分片)重组。
- 示例:4000 字节数据报(MTU=1500 字节)分为 3 片,首片数据 1480 字节(MTU-20 字节首部),段偏移 0,MF=1;末片数据 1040 字节,段偏移 370(1480×2/8),MF=0。
IPv4 地址体系与分类
IP 地址: 分配给主机或路由器接口的标识符,用于在网络中定位和区分设备。 接口: 主机/路由器与物理链路之间的边界。路由器有多个接口,主机可以有多个接口,每个接口有一个 IP 地址 IP 地址有两种:IPV4 和 IPV6 IPV4:32 个二进制位长(4 字节),常用点分十进制表示; IPV6:128 个二进制位长(16 字节)常用冒号分隔表示。
同一局域网上的主机或路由器的 IP 地址中的网络号必须相同。交换机互连的网络仍然是一个局域网,只能有一个网络号。路由器总是具有两个或两个以上 IP 地址。两个路由器直接相连时,在连线两端的接口处,可以指明 IP 地址也可以不指明 IP 地址。 IP地址结构 32 位二进制:点分十进制表示,如 223.1.1.1=11011111.00000001.00000001.00000001。 两部分组成:网络号(标识主机所在网络)+主机号(标识网络内主机)。 传统五类地址
| 类别 | 前缀标识 | 网络号长度 | 主机号长度 | 地址范围 | 适用场景 |
|---|---|---|---|---|---|
| A 类 | 首位 0 | 8 位 | 24 位 | 1.0.0.1-127.255.255.254 | 大型网络(如跨国企业) |
| B 类 | 前两位 10 | 16 位 | 16 位 | 128.0.0.1-191.255.255.254 | 中型网络(如大学) |
| C 类 | 前三位 110 | 24 位 | 8 位 | 192.0.0.1-223.255.255.254 | 小型网络(如企业部门) |
| D 类 | 前四位 1110 | - | - | 224.0.0.1-239.255.255.254 | 用于多播 |
| E 类 | 前五位 11110 | - | - | 240.0.0.1-255.255.255.254 | 为未来的需求保留的 |
| 特殊地址段 |
- 回环地址:127.0.0.1-127.255.255.254,用于本地环回测试,不对外通信。
- 私有地址:10.0.0.0-10.255.255.255(1 个 A 类块)、172.16.0.0-172.31.255.255(16 个 B 类块)、192.168.0.0-192.168.255.255(256 个 C 类块),仅限局域网使用,公网不路由。
- 特殊用途:0.0.0.0(未指定网络)、255.255.255.255(本网段广播地址)。
子网划分与子网掩码
子网的定义:设备接口的 IP 地址具有同样的网络部分。没有路由器的介入,物理上能够相互到达
-
划分子网原理
- 借位规则:从主机号高位借用 n 位作为子网号,剩余 m 位为主机号,子网数= ,每个子网主机数= (排除全 0 子网号和全 1 广播地址)。
- 示例:网段 202.114.1.0/24(C 类)划分为 2 个子网,借 1 位子网号,子网掩码 255.255.255.128(前 25 位 1),子网号为 0 和 128。
-
子网掩码计算
子网掩码长为 32 位比特,其中的 1 对应于 IP 地址中的网络号和子网号,而子网掩码中的 0 对应于主机号。
- 作用:子网号字段长度是可变的,因此,为了确定子网地址,IP 协议提供了子网掩码 。用于确定网络地址(网络号+子网号)和主机地址,通过 IP 地址与掩码按位与运算得到网络地址。 网络地址是 IP 地址的一部分,表示一个网络的 “标识符”,用于标识一个特定的网络。
- 示例:IP=187.163.22.11,掩码=255.255.255.128(二进制前 25 位 1),网络地址=187.163.22.0。
-
路由表变化
- 未划分子网:路由表含“目的网络地址”(存储网络地址而不是 IP 从而减少存储量)和“下一跳”,如 30.0.0.0→40.0.0.7。
- 划分子网后:增加“子网掩码”字段使得能够定位到子网,如 128.30.33.0/255.255.255.128→ 接口 0。
CIDR 无分类域间路由
传统 IP 地址分类方式分配 IP 被 CIDR 技术取代。使用斜线记法,又称为 CIDR 记法来区分网络前缀和主机号,即在 IP 地址后面加上一个斜线“/”,斜线后面用一个数字指定网络前缀的长度。即 CIDR 地址格式=网络前缀+主机号。
- 传统分类:A 类浪费(24 位主机号)、C 类不足(8 位主机号),地址利用率低。
- CIDR:按需分配地址块,支持超网聚合,解决地址浪费与不足问题,成为现代互联网主流编址技术。
-
核心技术特点
- 无类别编址:摒弃 A/B/C 类,用“IP 地址/网络前缀长度”表示(如 206.0.68.0/22),前缀长度可变(1-32 位)。
- 地址聚合:将连续网络前缀的地址块聚合成超网( 一个 CIDR 地址块可以表示分类 IP 的多个分类地址),减少路由表条目,提升路由效率。例如,4 个 C 类地址(206.0.68.0-206.0.71.255)可聚合成 206.0.68.0/22。
-
层次化地址分配
| 单位 | 地址块 | 二进制前缀 | 地址数 | 说明 |
|---|---|---|---|---|
| ISP | 206.0.64.0/18 | 11001110.00000000.01* | 16384 | 顶级分配块 |
| 大型单位 | 206.0.68.0/22 | 11001110.00000000.010001* | 1024 | 从 ISP 细分 |
| 中型单位 | 206.0.68.0/23 | 11001110.00000000.0100010* | 512 | 进一步细分 |
| 小型单位 | 206.0.71.0/25 | 11001110.00000000.01000111.0* | 128 | 最小分配单元 |
DHCP
问: 主机如何得到 IP 地址?
1.手工指定(保存在系统配置中):Windows: 控制面板->网络,UNIX/LINUX: 在/etc/rc.config 中,可使用 ipconfig 命令配置。 2.自动从一个 DHCP 服务器得到 IP 地址,方便灵活 DHCP(Dynamic Host Configuration Protocol,动态主机配置协议) 是一种用于自动分配网络配置参数的网络协议,应用层协议,基于客户机 / 服务器模型。其核心功能是为局域网内的设备动态分配 IP 地址、子网掩码、客户的第一跳路由器的地址(网关)、DNS 服务器 IP 地址或域名等网络参数,避免手动配置的繁琐和地址冲突问题。
工作过程
1:DHCP 服务器被动打开 UDP 端口 67,等待客户端发来的报文。
2:DHCP 客户从 UDP 端口 68 发送 DHCP 发现报文。
3:凡收到 DHCP 发现报文的 DHCP 服务器都发出 DHCP 提供报文,因此 DHCP 客户可能收到多个 DHCP 提供报文。
4:DHCP 客户从几个 DHCP 服务器中选择其中的一个,并向所选择的 DHCP 服务器发送 DHCP 请求报文。
5:被选择的 DHCP 服务器发送确认报文 DHCPACK,客户进入已绑定状态,并可开始使用得到的临时 IP 地址了。
DHCP 客户现在要根据服务器提供的租用期 T 设置两个计时器 T1 和 T2,它们的超时时间分别是 0.5T 和 0.875T。当超时时间到就要请求更新租用期。
6:租用期过了一半(T1 时间到),DHCP 发送请求报文 DHCPREQUEST 要求更新租用期。
7: DHCP 服务器若不同意,则发回否认报文 DHCPNACK。这时 DHCP 客户必须立即停止使用原来的 IP 地址,而必须重新申请 IP 地址(回到步骤 2)
8: DHCP 服务器若同意,则发回确认报文 DHCPACK。DHCP 客户得到了新的租用期,重新设置计时器。
若 DHCP 服务器不响应步骤 6 的请求报文 DHCPREQUEST,则在租用期过了 87.5% 时,DHCP 客户必须重新发送请求报文 DHCPREQUEST(重复步骤 6),然后又继续后面的步骤。
9:DHCP 客户可随时提前终止服务器所提供的租用期,这时只需向 DHCP 服务器发送释放报文 DHCPRELEASE 即可。
组织怎样获取 IP 地址中的网络号部分?从 ISP 的地址空间中划分一块给申请者
ISP 获得地址块的方法——从 ICANN 获取
NAT 网络地址转换
对外部网络来讲,本地网络只用一个 IP 地址,不需要从 ISP 分配一系列地址,一个 IP 地址用于所有设备。 在本地网络,改变设备的 IP 地址不用通知外部世界,可以变更 ISP ,不用改变本地网络的设备的地址。 本地网络内部设备不能被外部世界明确寻址,或是不可见 (增加了安全性)。
争议:网络地址端口转换需修改 TCP/UDP 端口号(第四层字段),但路由器只应该处理到第三层,违反了端到端主张
执行 NAT,路由器必须做到: 外出的分组: 替换每个外出的分组的 (源 IP 地址, 端口号) 为 (NAT IP 地址, 新端口号) 远程客户/服务器用(NAT IP 地址, 新端口号)作为目的地来响应。 (在 NAT 转换表中)记录每个(源 IP 地址, 端口号)到 (NAT IP 地址, 新端口号) 转换配对。 进来的分组: 对每个进来的分组,用保存在 NAT 表中的对应的(源 IP 地址, 端口号) 替换分组中的目的域 (NAT IP 地址, 新端口号)。
ICMP
(Internet Control Message Protocol,因特网控制报文协议),用于主机、路由器之间交流网络层信息,核心功能包含:
- 差错报告:告知网络层错误(如不可达的主机、网络、端口、协议等)。
- 请求/应答:支撑网络诊断工具(如
ping基于 ICMP 请求/应答;traceroute依赖 ICMP 超时报文 + 端口不可达报文 )。 - 协议层级:位于 IP 之上 ,ICMP 消息封装在 IP 分组中传输(即 ICMP 报文是 IP 分组的载荷 )。 PING 命令会向目标主机发送 ICMP Echo Request。 如果两个主机的连通性正常,目标主机会返回一个对应的 ICMP Echo Reply。
Traceroute:基于 ICMP 的路径追踪机制
traceroute 用于追踪数据包从源端到目的端的网络路径,并记录每一跳(路由器)的响应时间,其核心逻辑依托 TTL(生存时间) 和 ICMP 报文交互 实现:
- 源端发送 UDP 分组(利用 TTL 逐跳探测)
- 源端向目的端发送一系列 UDP 分组,特点是:
- 首组 TTL = 1,后续分组 TTL 逐次 + 1(如第二组 TTL = 2,第三组 TTL = 3 …… 以此类推 )。
- 使用高位未注册 UDP 端口(如 33434 及以上),目的端通常无对应服务监听。
- 路由器因 TTL 超时报文(ICMP Type 11)返回路径信息
- 当第 n 个 UDP 分组(TTL = n)到达第
n跳路由器时:- 路由器检测到 TTL 减为 0(或经自身转发后 TTL 耗尽 ),会丢弃该 UDP 分组。
- 同时,路由器向源端返回 ICMP 超时报文(Type = 11,Code = 0 ),报文中包含自身的名称和 IP 地址。
- 源端接收 ICMP 报文,计算 RTT 并记录路径
- 源端收到路由器返回的 ICMP 超时报文后:
- 计算往返时间 RTT(从发送 UDP 分组到收到 ICMP 报文的时间差 )。
- 为保证结果可靠性,对每个 TTL 值会发送 3 次 UDP 分组,取 RTT 统计值(如平均值、最小值 )。
- 目的端返回 ICMP 端口不可达,结束追踪
- 当 UDP 分组最终到达目的端时:
- 因目的端无对应 UDP 端口的服务(高位未注册端口 ),会返回 ICMP 端口不可达报文(Type = 3,Code = 3 )。
- 源端收到该报文后,判定路径追踪结束,停止发送后续 UDP 分组。
IPv6
采用 128 位二进制数 表示。IPv6 数据报格式:固定长度的 40 字节首部,不允许分片
例如:104.220.136.100.255.255.255.255.0.0.18.128.140.10.255.255 用冒号十六进制表示为: 69DC:8864:FFFF:FFFF:0:1280:8C0A:FFFF
零压缩表示法:前导零压缩,连续零段压缩。
例如:FF0C:0:0:0:0:0:B1 零压缩表示为:FF0C::B1
地址2001:0000:0000:0db8:0000:0000:7334可压缩为:2001::db8::7334
4.5 ⭐路由和选路
默认路由器:与主机直接相连的路由器,又叫第一跳路由器。每当主机发送一个分组时,都先传送给它的默认路由器。 从源主机到目的主机的选路归结为从源路由器到目的路由器的选路。 路由算法:是确定一个分组从源路由器到目的路由器所经路径的算法。 路由算法的关键:在给定的一组路由器以及连接路由器的链路中,找到一条从源路由器到目的路由器的“好”路径(开销最小,热土豆选路)。
路由算法分类:按信息获取方式分为全局路由算法(如链路状态路由算法 LS)和分布式路由算法(如距离向量路由算法 DV);按路径变化特性分为静态和动态路由算法。
链路状态路由算法(LS)
基于 Dijkstra 算法,所有节点知道网络拓扑和链路费用,通过链路状态广播实现,计算源节点到所有其他节点的最低费用路径,算法复杂度为 ,可能产生振荡。
c(x,y):表示从节点 x 到 y 的链路费用; = ∞ 如果不是直接邻居 D(v):表示从源节点到目的节点 v 的当前路径的费用; p(v):表示从源节点到目的节点 v 的路径上的前驱节点(例如 w 是 v 的前驱节点); N’:表示已经找到最低费用路径的节点集合。
例题
构建最低费用路径树
例题
距离向量路由算法(DV)
距离向量路由算法是一种迭代的、异步的和分布式的能自我终结算法。
分布式:每个节点都从其直接相连邻居接收信息,进行计算,再将计算结果分发给邻居。
对每个节点 x(1)初始化;(2)更新自己的距离向量:每个节点不断向邻居发送其距离向量拷贝;当节点 x 收到一个邻居 v 的新距离向量,先保存,并用 B-F 公式更新自己的距离向量 ;(3)重复执行(2),直到没有更新的距离向量发出
4.6 层次选路
层次选路指将大型网络(如因特网)划分成多个自治管理的区域(自治系统 AS 为典型单位 ),不同层次 / 区域内运行适配的路由协议,实现 “域内高效转发 + 域间策略控制” 的分层路由机制
域内路由协议
域内路由协议,也被称作内部网关协议 (IGP)。 标准的域内路由协议:RIP: 路由信息协议;OSPF: 开放式最短路径优先;IGRP: 内部网关路由协议 (Cisco 所有)
RIP(路由信息协议)
1. 工作原理
- 算法基础:基于 距离向量算法(Bellman-Ford 算法),通过“跳数”衡量路由距离(最大跳数为 15,16 表示不可达)。
- 更新机制:路由器周期性(默认 30 秒)向邻居节点广播自己的 路由表,内容包括目标网络、下一跳地址和跳数。
- 路由决策:选择跳数最少的路径,若跳数相同则任选其一(不支持负载均衡)。
2. 工作过程
- 初始化 路由器启动后,从直连网络获取路由信息(跳数为 0),并构建初始路由表。
- 周期性更新
每隔 30 秒,向所有 RIP 邻居(通过 UDP 520 端口)广播完整路由表。
- 邻居收到更新后,计算到达各目标网络的新跳数(自身跳数 + 1),若新路径更优(跳数更小),则更新路由表。
- 若超过 180 秒 未收到某条路由的更新,标记该路由为“不可达”(跳数设为 16);超过 240 秒 仍未更新,则从路由表中删除。
- 水平分割与毒性逆转
- 水平分割:禁止从接收路由的接口再发回该路由,避免简单环路。
- 毒性逆转:当路由不可达时,主动向邻居发送“跳数 16”的更新,加速环路破除。
- 路由收敛 网络拓扑变化时(如链路故障),故障路由器先更新自身路由表,再通过周期性更新逐步扩散到全网,收敛速度较慢(可能产生临时环路)。
OSPF(开放最短路径优先协议)
1. 工作原理
- 算法基础:基于 链路状态算法(Dijkstra 算法),通过“代价”(Cost,与带宽成反比)衡量路由优劣。
- 分层结构:将网络划分为 区域(Area),包括一个 骨干区域(Area 0) 和多个非骨干区域,区域间通过骨干区域通信,减少路由计算复杂度。
- 安全机制:支持认证(明文、MD5、SHA 等),确保路由更新的合法性。
- 多路径支持:允许等价路由(相同 Cost)实现负载均衡。
2. 工作过程
- 邻居发现 通过组播(224.0.0.5)发送 Hello 报文,发现相邻路由器并建立 邻居关系(需满足区域、认证、网络类型等匹配条件)。
- 邻接关系建立 邻居间通过 数据库描述(DBD)报文 交换链路状态数据库(LSDB)摘要,并用 链路状态请求(LSR) 和 链路状态更新(LSU) 报文同步完整 LSDB。 最终形成 邻接关系(仅在 DR/BDR 与其他路由器间或点到点网络中建立)。
- 链路状态更新 当网络拓扑变化时(如链路故障、路由器加入/退出),触发 LSU 报文 向全网泛洪(Flooding)更新信息,确保所有路由器的 LSDB 一致。 泛洪过程通过 序列号 和 校验和 保证可靠性,避免重复或过时的更新。
- 路由计算 每个路由器基于本地 LSDB,使用 Dijkstra 算法 计算到达所有目标网络的最短路径树(SPF Tree),生成 路由表。
- 路由维护
- 定期(默认 30 分钟)发送 Hello 报文 维持邻居关系。
- 当 LSDB 发生变化时,重新计算路由;若无变化,则不主动更新(仅周期性确认数据库同步)。
域间路由协议BGP
- AS 间选路的事实标准协议,用于实现跨自治系统的路由信息交换。
- 三个核心任务:
- 子网可达性管理:从相邻 AS 获取子网可达信息(如“AS2 可到达网络 X”),并向全网通告自身子网存在(“I am here”)。
- 可达性信息传播:通过 AS 内路由协议(如 OSPF)将域间路由同步到 AS 内所有路由器。
- 策略路由决策:基于 AS 策略和可达信息,选择到达目标子网的“好”路由(如优先选择客户网络路径)。
AS 域间任务与选路逻辑
- 任务场景:当 AS 内路由器收到发往域外的分组时,需决策转发至哪个网关路由器。
- 选路协作:
- 域间协议:获取跨 AS 的子网可达路径(如 AS1 通过 AS2 和 AS3 均可达网络 X)。
- 域内协议:计算 AS 内到各网关的最低开销路径(如 Router 1d 通过接口 I 到达网关 1c 的开销最小)。
- 热土豆选路(Hot Potato Routing):优先选择 AS 内到网关最小开销路径的网关,即使跨 AS 路径更长(如 AS1 选择更近的网关 1c 而非 1b)。
BGP 会话机制与信息传播
- 会话类型:
| 类型 | 作用 | 通信对象 | TCP 端口 | TTL 限制 |
|---|---|---|---|---|
| eBGP | 跨 AS 路由交换 | 不同 AS 路由器 | 179 | 默认 1 |
| iBGP | AS 内路由同步 | 同 AS 路由器 | 179 | 默认 255 |
-
通告流程:
- eBGP 会话:AS3 通过路由器 3a 向 AS1 的 1c 通告前缀 X 可达。
- iBGP 扩散:1c 通过 iBGP 会话将前缀 X 同步到 AS1 内所有路由器(如 1d、1b)。
- 跨 AS 再通告:1b 通过 eBGP 会话向 AS2 的 2a 通告前缀 X 可达。
路径属性与路由构成
-
路由定义:前缀+路径属性=路由,属性用于描述路由特征和策略。
-
核心属性:
| 属性名称 | 作用 |
|---|---|
| AS-PATH | 记录路由经过的 AS 列表(如“AS3 AS1”),用于防环(拒绝包含自身 AS 的路由) |
| NEXT-HOP | 指示跨 AS 的下一跳路由器 IP(如 AS1 到 AS3 的下一跳为 1c) |
- 策略应用:网关路由器通过输入策略过滤路由(如 AS1 拒绝 AS2 的非客户路由)。
BGP 选路规则与优先级
- 排除规则:按顺序筛选,直至仅剩一条路由。
- 核心优先级:
- 本地偏好值(Local Preference):AS 内自定义优先级,值越高越优先(如优先选择本 AS 出口)。
- AS-PATH 长度:路径越短越优先(如 AS3→AS1 优于 AS3→AS2→AS1)。
- NEXT-HOP 距离:AS 内到网关的开销越小越优先(热土豆选路)。
BGP 报文类型与功能
| 报文类型 | 功能描述 |
|---|---|
| OPEN | 建立 TCP 连接,协商版本、AS 号,完成认证 |
| UPDATE | 通告新路由(携带前缀和属性)或撤销旧路由(携带不可达前缀列表) |
| KEEPALIVE | 周期性(默认 30 秒)维持会话连接,确认邻居存活 |
| NOTIFICATION | 报告协议错误(如格式错误、认证失败),终止会话 |
eBGP 与 iBGP 会话的核心区别
eBGP:用于不同 AS 间的路由交换,默认 TTL=1(限制跨 AS 跳数),需显式配置邻居关系,路由通告时携带完整 AS-PATH。
iBGP:用于同一 AS 内的路由同步,TTL=255(允许跨多个路由器),无需物理直连,需遵守“iBGP 水平分割”原则(不从接收接口转发 iBGP 路由,避免环路)。
4.7 软件定义网络 SDN
- 概念与特点:软件定义网络是一种网络设计理念,具有控制平面和转发平面分离、开放性可编程的特点。SDN 的核心思想是建立一个通用转发体系——每个交换设备包含一个流表(flow table)。 流表由一个逻辑上中心化的控制器(远程控制器)来计算和分发。
- 相关案例与优势:Google 用 SDN 互联数据中心,提升带宽利用率,降低故障收敛时间。SDN 具有统一管理、解决设备多样化等优势。
第五章 数据链路层
5.1 概述
链路层核心职责
-
将数据报从一个节点(主机或路由器)通过物理链路(有线或无线)传输到相邻节点。
-
处理对象:相邻节点间的单跳通信(区别于网络层的端到端通信)。
-
数据帧(Frame):链路层的协议数据单元,由数据报+帧头/帧尾封装而成,用于在链路上传输。在数据帧头部中,用 MAC 地址来标识源目的 MAC 地址。
链路层提供的服务和以太网能够提供的链路层服务是两个不同的概念。
第一个服务是:将数据报封装成数据帧,增加相应的头部和尾部信息,然后对于共享链路,能够接入链路
第二个服务是:在相邻节点之间可靠传输数据帧,当传输链路是比特错误率很低的链路时,例如光纤和双绞线,很少使用可靠数据传输机制;而在无线链路这样的高比特错误率链路时,通常会增加可靠数据传输机制。
思考一个问题:既然在传输层实现了端到端的可靠数据传输,为什么还需要在链路层提供可靠数据传输呢?
链路层负责相邻节点(主机 - 路由器、路由器 - 路由器等) 间的可靠传输,仅关注 “一段物理链路” 的数据转发。若链路层不保证可靠,即使传输层有端到端机制,局部链路的错误也会拖慢整体传输效率。
链路层六个主要服务
| 服务类型 | 功能描述 | 技术实现 |
|---|---|---|
| 封装成帧,链路接入 | 将网络层数据报封装为数据帧,添加帧头(源/目的 MAC 地址等)和帧尾(校验信息)。 | 帧头包含MAC 地址(标识相邻节点),帧尾通常含CRC 校验码。 |
| 可靠传输 | 确保数据帧在相邻节点间无差错、有序交付(非所有链路层必选,如以太网无此服务)。 | 差错检测:CRC 校验。 重传机制:ARQ 协议(停止等待、滑动窗口)。 序号与确认。 |
| 流量控制 | 限制发送方速率,避免接收方缓冲区溢出。 | 滑动窗口协议(如 TCP 链路层的流量控制)。 接收方反馈“窗口大小”通知发送方。 |
| 差错检测 | 检测传输中因噪声等导致的比特错误。 | CRC(循环冗余校验)、奇偶校验等算法,通过帧尾校验字段实现。 |
| 差错纠正 | 自动纠正检测到的比特错误(较少用,因重传更高效)。 | 海明码等前向纠错(FEC)技术,常见于无线链路(如 802.11)。 |
| 双工模式 | 半双工:节点不能同时收发数据(如早期以太网)。 全双工:可同时收发(现代主流模式)。 | 取决于物理链路特性和设备支持(如双绞线支持全双工,同轴电缆仅半双工)。 |
链路层的实现位置
在主机和网络设备(路由器)上实现,是硬件,软件,固件的组合。在主机上,链路层的主体部分是在网络适配器上实现的(称为网卡)。
链路层控制器的许多功能是用硬件实现的。
在发送方,链路层控制器将数据报封装成数据帧,增加差错检测比特,可靠数据传输,流量控制等机制。
在接收方,链路层控制器接收数据帧,执行差错检测、可靠数据传输、流量控制等机制,最后从数据帧中抽取数据报,递交给上层。
链路层与 MAC 地址
-
MAC 地址(物理地址)
- 定义:固化在网络适配器(网卡)中的48 位标识符,全球唯一(由 IEEE 分配前 24 位厂商代码,后 24 位厂商自定义)。
- 作用:标识链路层通信的源/目的节点(区别于网络层的 IP 地址,IP 地址标识端到端通信的逻辑主机)。
- 示例:
00:1A:2B:3C:4D:5E(十六进制表示)。
-
MAC 地址与 IP 地址的区别
| 维度 | MAC 地址 | IP 地址 |
|---|---|---|
| 层次 | 链路层(硬件标识) | 网络层(逻辑标识) |
| 作用范围 | 相邻节点间的单跳通信 | 端到端的跨网络通信 |
| 动态性 | 固定(除非更换网卡) | 动态分配(如 DHCP)或静态 |
| 协议关联 | 用于以太网帧、802.11 帧等 | 用于 IP 数据报 |
5.2 差错检查和纠错
概述
这里的差错检测和纠正技术主要针对的是比特错误。对一个节点发送到一个相邻节点的帧,检测是否出现比特差错,并纠正。
差错检测并非 100%可靠,协议可能丢失一些错误,差错校验位越多,检测和纠正功能越好。
发送节点
接收节点
三种检测技术
奇偶校验
将要传信息 D(d 比特)划分为 i 行 j 列(i 个组,每组 j 位);对每行和每列分别计算奇偶值;结果的 i+j+1 个奇偶比特构成了帧的差错检测比特。
二维奇偶校验
Internet 校验和
**发送方:**将数据的每两个字节当作一个 16 位的整数,可分成若干整数;将所有 16 位的整数求和;对得到的和逐位取反,作为检查和,放在报文段首部,一起发送。
接收方: 对接收到的信息 (包括检查和)按与发送方相同的方法求和。全“1”:收到的数据无差错;其中有“0”:收到的数据出现差错。
优缺点:分组开销小:检查和位数比较少;差错检测能力弱。适用于运输层(差错检测用软件实现,检查和方法简单、快速)。 链路层的差错检测由适配器中专用的硬件实现,采用更强的 CRC 方法。
循环冗余检测
特点:高效,能检查几乎所有错误,但无法纠正。广泛使用。
- 多项式表示
将二进制数据视为多项式,例如二进制串
1011对应多项式 。- 收发双方预先约定一个生成多项式 ,其最高次幂为
- 编码过程(发送端)
- 计算出一个 r 位附加比特 R,添加到 D 的后面产生 DR(d+r 比特)。DR 能被生成多项式 G 模 2 运算整除,一起发送。
- 校验过程(接收端)
- 对接收到的数据多项式 用同样的 做除法运算。若余数为
0,则认为数据无差错;否则判定为有误。
- 对接收到的数据多项式 用同样的 做除法运算。若余数为
模 2 运算:加法不进位,减法不借位,即操作数按位异或 (XOR),乘以 2 的r次幂,即比特模式左移r个位置
例题:
假设数据 D 为 101110,生成多项式 G 为 1001,CRC 编码为 3 比特,是生成多项式的位数减 1。
这里用模 2 运输,计算 CRC 编码。首先将 D 乘以 2 的 3 次方,即可得 101110000;
然后将 101110000 除以生成多项式 1001,最后可得余数为 0011,因为 CRC 编码只取 3 比特,因此为 011。
因此发送方最终发送的数据为 101110011。
5.3 多路访问链路和协议
广播链路
两种网络链路: 1.点对点链路:链路两端各一个节点。一个发送和一个接收。如点对点协议 PPP。 2.广播链路: 多个节点连接到一个共享的广播信道。
共享广播信道是非常常见的,例如我们在公众场合说话都是属于共享信道。这种共享信道的特点是:当一个人在说话时,其他人需要安静的听,如果有多个人同时说话,会导致收听的人听不清楚,这就是产生了干扰。广播信道中的每个节点都可能发送和接收数据帧,如果多个节点同时向共享信道发送数据,会导致信道中的信号相互干扰,使数据帧不能正确接收。
如何协调多个发送和接收节点对共享广播信道的访问,相关技术即是多路访问协议(也称多址访问协议)
多路访问协议
目的:协调多个节点在共享广播信道上的传输。避免多个节点同时使用信道,发生冲突(碰撞),产生互相干扰。 冲突是指:两个以上的节点同时发送帧,使接收方收不到正确的帧(所有冲突的帧都受损丢失)。
理想的多址访问协议,对于速率为 R bps 的广播信道
- 当一个节点有数据发送时,它能以 R bps 的速率发送.
- 当有 M 个节点要发送数据,每个节点的平均发送速率为 R/M
- 完全分散:不需要主节点协调传输,不需要时钟、时隙同步
- 简单
信道划分协议
把信道划分为小“片” (时隙),给节点分配专用的小“片” ,设信道支持 N 个节点,传输速率是 R b/s。 时分多路访问 TDMA (time division multiple access):将时间划分为时间帧,每个时间帧再划分为 N 个时隙(长度保证发送一个分组),分别分配给 N 个节点。每个节点只在固定分配的时隙中传输。
优缺点:避免冲突、公平,每个节点专用速率 R/N b/s,但这也是上限,同时效率低--节点必须等待它的传输时隙。
频分多路访问 FDMA (frequency division multiple access):将总信道带宽 R b/s 划分为 N 个较小信道(频段,带宽为 R/N),分别分配给 N 个节点。
码分多路访问 CDMA (Code Division Multiple Access):每个节点分配一个唯一的编码,每个节点用它唯一的编码来对它发送的数据进行编码,允许多个节点“共存” ,信号可叠加,即可以同时传输数据而无冲突 (如果编码 是“正交化”的)
随机访问协议
不划分信道,允许冲突,能从冲突中“恢复”。
基本思想:发送节点以信道全部速率(R b/s)发送;发生冲突时,冲突的每个节点分别等待一个随机时间,再重发,直到帧(分组)发送成功,节点间没有协调者。
纯 ALOHA: 非时隙 Aloha: 简单,不需同步。帧一到达,立即传输。 如果与其他帧产生冲突,在该冲突帧传完之后:以概率 p 立即重传该帧;或等待一个帧的传输时间,再以概率 p 传输该帧,或者以概率 1-p 等待另一个帧的时间。冲突可能性:在 t0 发送的帧,和在 [t0-1,t0+1]的发送的其它帧冲突。效率:约 18%(1/(2e))。
时隙 ALOHA:假设所有帧大小相同,时间被划分为相同大小的时隙,一个时隙等于传送一帧的时间,节点只能在一个时隙的开始才能传送,节点需要同步,如果一个时隙有多个节点同时传送,所有节点都能检测到冲突。过程:当节点要发送新帧,它等到下一时隙开始时传送;没有冲突,节点可以在下一时隙发送新帧;如果有冲突,节点在随后的时隙以概率 p 重传该帧,直到成功为止。
优点:单个活跃节点可以持续以满速率传送帧, 只需节点的时隙同步,简单。缺点是浪费时隙。效率:37%(1/(e))。
CSMA 载波侦听多路访问:载波侦听:某个节点在发送之前,先监听信道。 信道忙:有其他节点正往信道发送帧,该节点随机等待一段时间(回退),然后再侦听信道。 信道空:该节点开始传输整个数据帧。
由于传播时延的存在,仍有可能出现冲突,并造成信道浪费
带冲突检测的 CSMA(CSMA/CD):增加“载波侦听”和“冲突检测”两个规则。发送数据帧时,同时进行冲突检测:一旦检测到冲突就立即停止传输, 尽快重发。目的:缩短无效传送时间,提高信道的利用率。
以太网也是采用 CSMA/CD 机制来访问共享信道,检测到碰撞后,进行二进制指数算法回退。
二进制指数算法回退
轮流协议
通过轮流访问信道避免冲突,要发送的节点越多轮流时间越长
轮询协议:主节点按顺序邀请从节点传输,从节点仅在被邀请时发送数据。轮询指令产生额外开销;主节点故障导致全网瘫痪;节点多时有明显延时
令牌传递协议:网络中传递 “令牌”,仅持有令牌的节点可传输,传输完成后将令牌传递给下一节点。
令牌丢失或损坏导致网络瘫痪;令牌传递引入延时,节点越多效率越低。
5.4 交换局域网
局域网:Local Area Network ( LAN ),网络为一个组织所拥有,且地理范围和站点数目均有限
按拓扑结构进行分类:星形网(中央结点辐射状连接)、环形网(站与站点之间首尾相接,形成一个环,数据只能沿单方向传输。适合光纤,实时性强)、总线网(站点都连接在同一根传输线,易于扩展)、树形网和网状网(网状网络的每一个站点都与其它站点一一直接互连,能高速传输高容错,但关系复杂维护难)
计算机与局域网通过网络接口板(网卡)进行连接。网卡属于物理层,网卡驱动程序属于数据链路层。
链路层寻址和 ARP
每个节点有网络层地址和链路层地址。应用层主机名如域名不一定有。 网络层地址:节点在网络中分配的一个唯一地址(IP 地址)。用于把分组送到目的 IP 网络。长度为 32 比特(IPv4)。 链路层地址:又叫做MAC 地址或物理地址、局域网地址。用于把数据帧从一个节点传送到另一个节点(同一网络中)。 MAC 地址(LAN 地址、物理地址):节点“网卡”本身所带的地址(唯一)。MAC 地址长度通常 6 字节,地址用 16 进制表示,每个字节表示为一对 16 进制数,前三个字节向 IEEE 购买,后三个由厂家自行分配。网卡的 MAC 地址是永久的(生产时固化在其 ROM 里)
MAC 地址识别
由“网卡”负责 MAC 地址的封装和识别。 发送适配器:将目的 MAC 地址封装到帧中,并发送。所有其他适配器都会收到这个帧。 接收适配器:检查帧的目的 MAC 地址是否与自己 MAC 地址相匹配: 匹配:接收该帧,取出数据报,并传递给上层。不匹配:丢弃该帧。 广播帧:发送给所有节点的帧,目的 MAC 地址需要用广播地址——全 1 地址:FF-FF-FF-FF-FF-FF
地址转换
过程:主机名 - ->IP 地址 --> MAC 地址
DNS 域名系统:将主机名解析到 IP 地址。DNS 为在因特网中任何地方的主机解析主机名。 ARP 地址解析协议:将 IP 地址解析到 MAC 地址。ARP 只为在同一个 LAN 上的节点解析 IP 地址。
ARP 表: 局域网上的每个节点(主机、路由器)都有这个表,为某些局域网节点进行 IP/MAC 地址映射:< IP address; MAC address; TTL> TTL (存活时间): 地址映射将被删除的时间(通常为 20 分钟)
假设同一个局域网中:主机 A 希望发送数据报给主机 B,主机 A 首先查找自己维护的 ARP 表,看是否存在 B 的 MAC 地址,假设 B 的 MAC 地址不在 A 的 ARP 映射表中。则主机 A 首先广播 ARP 查询分组,其中包含 B 的 IP 地址,查询分组是个广播帧,即目的 MAC 地址是 FF-FF-FF-FF-FF-FF。因此局域网中所有节点收到 ARP 查询分组,其余主机发现查询的不是本机的 MAC 地址,因此不进行回应。只有主机 B 收到 ARP 查询分组后,返回 B 的 MAC 地址给主机 A,包含有 B 的 MAC 地址的帧发送给主机 A(单播)。于是,主机 A 在自己的 ARP 表中缓存 B 主机的 IP 地址和 MAC 地址。
发送数据报到子网之外:主机 A 经路由器 R 发送数据报给主机 B,假设主机 A 知道主机 B 的 IP 地址,假设主机 A 知道第一跳路由器 R 的 IP 地址(通过 DHCP 协议),假设主机 A 知道路由器 R 的 MAC 地址(通过 ARP 协议)。主机 A 构建 IP 数据报,源地址是 A 的 IP 地址,目的地址是 B 的 IP 地址主机 A 构建链路层数据帧,目的 MAC 地址是路由器左边端口的 MAC 地址(靠近 A 的那一端)。数据帧从主机 A 发送到路由器 R,路由器 R 收到数据帧,抽取出数据报递交到 IP 层。路由器 R 转发数据报,源地址为 A 的 IP 地址,目的地址为 B 的 IP 地址,路由器 R 将该数据报封装成链路层帧,目的 MAC 地址为主机 B 的 MAC 地址
以太网 Ethernet
以太网技术是最著名的有线局域网技术,常见有两种物理拓扑结构,常用 5 类和超 5 类双绞线。
总线型:一直流行到 90 年代中期,所有节点都属于相同的冲突域
星形:目前仍然非常流行,星形结构的中心是交换机,每个端口运行一个独立的以太网协议,节点相互之间发送数据帧不发生碰撞,每个端口对应的网段是一个独立的碰撞域。
以太网链路层技术:数据封装(帧同步、帧定界;地址确定;错误检测机制),媒体访问管理(媒体分配(避免冲突),冲突解决(冲突处理))
以太网帧结构
前同步码:“前 7 字节是“10101010”,最后一个字节是“10101011”。使接收方和发送方的时钟同步,接收方一旦收到连续的 8 字节前同步码,可确定有帧传过来。前同步码是“无效信号”,接收方收到后删除,不向上层传。CRC 的校验范围不包括前同步码。
源、目的 MAC 地址(各 6 字节):适配器 B 只接收目的地址与其 MAC 地址匹配或广播地址的帧,并将数据字段的内容传递给网络层。否则,丢弃该帧。
类型:主要是支持以太网中的多种网络层协议的复用的,绝大多数是指 IP 协议
数据字段:携带网络层传来的 IP 数据报,若 IP 数据报超过 1500 字节,必须将该数据报分段。最小长度是 46 字节:如果 IP 数据报小于 46 字节,必须填充为 46 字节。接收方网络层去除填充内容。
以太网提供的是不可靠的无连接服务。无连接:无需握手。不可靠:收到正确帧,不发确认帧;收到出错帧,丢弃该帧,不发否定帧。不重发出错帧。使用无时隙的 CSMA/CD 协议(二进制指数回退)
链路层交换机
交换机是属于链路层的设备,其主要作用是存储转发数据帧。对于到达交换机的数据帧,交换机首先检查其目的 MAC 地址,然后根据 MAC 地址,有选择的将数据帧转发到一个或多个输出链路;如果输出链路是一个共享网段,将使用 CSMA/CD 来访问共享链路。第二个特点是透明,这里的透明是指的当一个主机向另一个主机发送数据帧时,它并不会知道某个交换机会收到这个数据帧,并将其转发到另一个节点。交换机无需手工配置,即插即用。
交换机可以支持多个节点同时传输数据帧。每个主机由单独的链路与交换机端口相连,因此交换机每个端口对应的链路和主机是一个独立的碰撞域。交换机对于收到的数据帧可进行缓存。
机制:识别目的 MAC 地址,根据交换表进行端口选择。识别源 MAC 地址更新交换表。
自学习机制:每当交换机收到一个数据帧时,交换机会学习发送主机的位置及进入的局域网段和到达端口,并在转发表中进行记录。
当交换机收到数据帧进行查表转发的过程:
1.记录到达链路和发送主机的 MAC 地址
2.使用数据帧的目的 MAC 地址,在转发表中检索
3.如果在转发表条目中找到对应的 MAC 地址
4.执行: 如果 目的 MAC 地址对应的端口与数据帧的达到端口相同 则 丢弃该数据帧 否则 转发该数据帧到条目指定的端口
5.否则,向除到达端口之外的所有端口转发(flood,泛洪)。目标主机如果在某个端口下,就会响应,发送一个数据帧回来。这时候交换机收到响应帧,会学习源 MAC(即目标主机的 MAC)和对应的端口。
例题
交换机的交换方式
存储转发(缓存整个帧后再转发),具有差错检测功能,转发时延较大,适用于出错率高的链路。
快速分组又称直通交换(识别出目的地址直接转发),不具有差错检测功能,转发时延较小,适用于时延要求高,出错率低的链路。
三层交换机
传统的交换技术在 OSI 模型的第二层即数据链路层做交换,而三层交换技术就是在第三层即网络层做交换,本质上是二层交换技术+三层转发技术,三层交换机就是“二层交换机+基于硬件的路由器”
工作原理
发送站点 A 在开始发送时,把自己的 IP 地址与 B 站的 IP 地址比较,判断 B 站是否与自己在同一子网内。
若目的站 B 与发送站 A 在同一子网内,则进行二层的转发。
若两个站点不在同一子网内,则发送站 A 要向“缺省网关”发出 ARP 请求,请求获得 B 的 MAC 地址。
如果三层交换机知道 B 的 MAC 地址,则向 A 回复 B 的 MAC 地址。否则三层交换机根据路由信息向 B 站广播一个 ARP 请求,B 站得到此 ARP 请求后向三层交换机回复其 MAC 地址,三层交换机将 B 站的 MAC 地址保存到二层交换引擎的 MAC 地址表中,并回复给发送站 A。
A 直接用 B 的 MAC 地址封装数据帧,三层交换机接收到数据后直接进行二层交换。
VLAN
基于端口的 VLAN: 利用交换机内置的管理软件,将端口分组,使得一个单独的交换机像多个交换机那样工作。分属不同的虚假交换机端口间有流量隔离。
第六章 套接字编程
6.1 网络编程基础
服务器: 总是打开的主机,具有固定的、众所周知的 IP 地址,主机群集常被用于创建强大的虚拟服务器 客户机:同服务器端通信,可以间断的同服务器连接,可以拥有动态 IP 地址,客户机相互之间不直接通信
网络字节顺序
采用大端排序方式,总是从低位地址开始传输。发送数据包时,程序将主机字节序转换为网络字节序;接受收数据包时,则将网络字节序转换为主机字节序。
数据结构对齐
是由编译器对代码进行处理来实现,防止内存的二次访问,一次性取出所需数据。每个特定平台的编译器都有自己的默认“对齐系数” 。
结构体对齐规则: 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 结构体每个成员相对结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节; 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节
接口协议
1.TCP/IP 协议存在于 OS 中,网络服务通过 OS 提供
2.TCP/IP 要尽量避免让接口使用某一个厂商的 OS 中特有的特征(而其他厂商没有)
3.TCP/IP 和应用程序之间的接口应该不精确指明:
① 不规定接口的细节 ② 只建议需要的功能集 ③ 允许系统设计者选择有关 API 的具体实现细节
提供了灵活性和容错能力,但移植性差
POSIX 表示可移植操作系统接口,源代码级别的软件可移植性
系统调用
为安全考量,诸如 I/O 操作等特权指令被限制在内核态模式执行,系统调用使得应用程序从操作系统获得服务。
open:返回文件描述符(file descriptor)
int desc;
desc = open(“filename”, O_RDWR, 0);
read:利用上述文件标识符
read(desc, buffer,128);
write:与open, read类似
close:撤销标识符并释放资源
close(desc);
将 Linux I/O 用于 TCP/IP
1.扩展文件描述符,可用于网络通信 2.扩展 read,write,可用于操作网络标识符
3.额外功能的处理,通过增加新系统调用实现:
① 指明本地和远端的端口,远程 IP 地址 ② 使用 TCP 还是 UDP
③ 启动传输还是等待传入连接 ④ 可以接受多少传入连接 ⑤ 传输 UDP 数据
Socket
定义: Socket 是操作系统提供的协议操作接口,而非协议本身。它是本地应用程序创建的通信接口,遵循 Client/Server 模式,允许应用进程通过传输层服务,跨网络发送或接收消息。
Socket 的分类与工作模式
按角色分类:
- 被动套接字:等待传入连接(如服务器套接字)。
- 主动套接字:发起连接(如客户端套接字)。
核心特性:
- 端到端地址在创建时不指定,使用时需明确(如 TCP/IP 需指定协议端口号和 IP 地址)。
TCP/IP 协议族中的 Socket 关键概念
- 协议族与地址族:
- PF_INET:TCP/IP 协议族(Protocol Family)。
- AF_INET:TCP/IP 地址族(Address Family)。
- 设计逻辑:早期设计认为一个协议族可能对应多种地址形式,因此 API 中将 PF(创建 socket 时使用)与 AF(绑定/连接时使用)分开。但实际应用中,一个 PF 仅对应一个 AF,二者可混用。
- 支持的通信协议(地址族):
- Unix:Unix 系统内部协议。
- INET(AF_INET):IPv4 协议。
- INET6(AF_INET6):IPv6 协议。
Socket 类型与对应通信服务
| Socket 类型 | 通信特性 | 对应传输层协议 |
|---|---|---|
| SOCKET_DGRAM | 双向不可靠数据报(无连接) | UDP |
| SOCKET_STREAM | 双向可靠数据流(面向连接) | TCP |
| SOCKET_RAW | 访问低级协议或物理网络接口 | 原始套接字(如 IP 层) |
地址结构
Socket 通用地址结构 sockaddr 的局限
- Socket 的本质与编址需求 Socket 是传输层/网络层的编程接口,由于不同传输层/网络层实现(如 IPv4、IPv6、本地通信等)采用不同的编址方案,因此需要定义通用地址结构来适配多种场景。
- sockaddr 结构的局限性
通用地址结构
sockaddr虽为适应多编址方案而设计,但实际通用性有限: 对于AF_INET6(IPv6)或AF_LOCAL(本地套接字)等类型的 Socket 地址,sockaddr结构仅能标识地址类型,无法完整描述地址细节(如具体 IP 地址、端口等)。
地址转换函数的作用
- 地址表示的矛盾
人们习惯用点分十进制字符串(如
202.112.14.151)表示 IP 地址,但此类字符串本质上非数值类型,无法直接用于 Socket 编程中的底层网络通信(底层接口需数值型地址)。 - 转换的必要性
因此,在 Socket 编程时,需通过地址转换函数(如
inet_pton、inet_ntop等)实现字符串地址与数值地址的相互转换,确保程序能正确解析和使用网络地址。
int inet_pton(int family, const char *src, void *dst)
返回:1-成功,0-输入无效,-1:出错
将src指向的字符串转换成二进制地址数值放到dst中。
const char *inet_ntop(int family, const void *src, char *dst, size_t cnt)
返回:指向结果的指针--成功,NULL-出错
和pton做相反的操作。
family参数可以是AF_INET,也可以是AF_INET6。
如果长度参数cnt太小,无法容纳表达式格式结果,则返回一个空串。另外,目标指针dst调用前必须先由调用者分配空间。
6.2 Socket 套接字与循环服务器
简单 TCP 循环服务器 Socket 编程基本步骤 ⭐
服务器端:创建套接字,绑定套接字,设置套接字为监听模式,进入被动接受连接状态,接受请求,建立连接,读写数据,终止连接
客户端:创建套接字,与远程服务器建立连接,读写数据,终止连接
简单 UDP 循环服务器 Socket 编程基本步骤
服务器端:建立 UDP 套接字;,绑定套接字到特定地址;,等待并接收客户端信息;,处理客户端请求;,发送信息回客户端;,关闭套接字;
客户端:建立 UDP 套接字;,发送信息给服务器;,接收来自服务器的信息;,关闭套接字
Socket 核心函数用法整理
#include <sys/socket.h>
1. int socket (int family, int type, int protocol);
returns: non-negative descriptor if OK, -1 on error
功能:创建套接字,返回描述符。
参数:
family:协议族(如 AF_INET 表示 TCP/IP)。
type:服务类型(SOCK_STREAM 为 TCP,SOCK_DGRAM 为 UDP)。
protocol:协议字段,通常为 0。
2. int bind (int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
returns: 0 OK, -1 on error
功能:绑定本地地址(IP + 端口)到套接字。
参数:
sockfd:套接字描述符。
myaddr:本地地址结构体(如 sockaddr_in)。
addrlen:地址长度。
3. int listen (int sockfd, int backlog);
returns: 0 OK, -1 on error
功能:将套接字设为被动监听状态,准备接收连接。
参数:
sockfd:套接字描述符。
backlog:连接队列最大长度。
4. int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
returns: non-negative descriptor if OK, -1 on error
功能:接受客户端连接,创建新套接字用于数据传输。
参数:
sockfd:监听套接字描述符。
cliaddr:客户端地址结构体指针。
addrlen:地址长度指针。
5. int connect (int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
returns: 0 if OK, -1 on error
功能:客户端主动连接远程服务器。
参数:
sockfd:套接字描述符。
servaddr:服务器地址结构体。
addrlen:地址长度。
6. int send(int sockfd, const void * data, int data_len, unsigned int flags)
返回值:成功返回发送字节数,失败返回 -1。
功能:在 TCP 连接上发送数据。
参数:
sockfd:套接字描述符。
data:数据指针。
data_len:数据长度。
flags:标志位(通常为 0)。
7. int sendto(int sockfd, const void * data, int data_len, unsigned int flags, struct sockaddr *remaddr, int remaddr_len)
返回值:成功返回发送字节数,失败返回 -1。
功能:在 UDP 上发送数据报,需指定目标地址。
参数:
sockfd:套接字描述符。
data:数据指针。
data_len:数据长度。
flags:标志位(通常为 0)。
remaddr:目标地址结构体。
remaddr_len:地址长度。
8. int recv(int sockfd, void *buf, int buf_len,unsigned int flags);
返回值:成功返回接收字节数,失败返回 -1。
功能:在 TCP 连接上接收数据。
参数:
sockfd:套接字描述符。
buf:接收缓冲区指针。
buf_len:缓冲区大小。
flags:标志位(通常为 0)。
9.int recvfrom(int sockfd, void *buf, int buf_len, unsigned int flags, struct sockaddr *from, int fromlen); 返回值:成功返回接收字节数,失败返回 -1。
功能:在 UDP 上接收数据报,获取发送方地址。
参数:
sockfd:套接字描述符。
buf:接收缓冲区指针。
buf_len:缓冲区大小。
flags:标志位(通常为 0)。
from:发送方地址结构体指针。
fromlen:地址长度指针。
10. Int close(int sockfd);
返回值:成功返回 0,失败返回 -1。
功能:关闭套接字(释放文件描述符)。
参数: sockfd:套接字描述符。
以下示例展示了 TCP 服务器/客户端和 UDP 通信的完整流程:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT_TCP 8080
#define PORT_UDP 9090
#define BUFFER_SIZE 1024
// TCP 服务器示例
void tcp_server() {
int sockfd, newsockfd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[BUFFER_SIZE];
// 创建 TCP 套接字
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 填充服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT_TCP);
// 绑定地址
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(sockfd, 5) < 0) {
perror("listen failed");
exit(EXIT_FAILURE);
}
printf("TCP Server listening on port %d...\n", PORT_TCP);
// 接受客户端连接
if ((newsockfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len)) < 0) {
perror("accept failed");
exit(EXIT_FAILURE);
}
printf("TCP Client connected: %s:%d\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 接收数据
int recv_bytes = recv(newsockfd, buffer, BUFFER_SIZE, 0);
if (recv_bytes > 0) {
buffer[recv_bytes] = '\0';
printf("TCP Received: %s\n", buffer);
}
// 发送响应
const char *response = "Hello from TCP server!";
send(newsockfd, response, strlen(response), 0);
// 关闭套接字
close(newsockfd);
close(sockfd);
}
// TCP 客户端示例
void tcp_client() {
int sockfd;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
// 创建 TCP 套接字
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 填充服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT_TCP);
// 转换 IP 地址(示例使用本地回环地址)
if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {
perror("invalid address");
exit(EXIT_FAILURE);
}
// 连接服务器
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("connect failed");
exit(EXIT_FAILURE);
}
// 发送数据
const char *message = "Hello from TCP client!";
send(sockfd, message, strlen(message), 0);
// 接收响应
int recv_bytes = recv(sockfd, buffer, BUFFER_SIZE, 0);
if (recv_bytes > 0) {
buffer[recv_bytes] = '\0';
printf("TCP Received: %s\n", buffer);
}
// 关闭套接字
close(sockfd);
}
// UDP 通信示例
void udp_communication() {
int sockfd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[BUFFER_SIZE];
// 创建 UDP 套接字
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 填充服务器地址(用于接收)
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT_UDP);
// 绑定地址
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("UDP Server listening on port %d...\n", PORT_UDP);
// 接收 UDP 数据报(同时获取客户端地址)
int recv_bytes = recvfrom(sockfd, buffer, BUFFER_SIZE, 0,
(struct sockaddr *)&client_addr, &client_len);
if (recv_bytes > 0) {
buffer[recv_bytes] = '\0';
printf("UDP Received from %s:%d: %s\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);
}
// 发送 UDP 响应
const char *response = "Hello from UDP server!";
sendto(sockfd, response, strlen(response), 0,
(struct sockaddr *)&client_addr, client_len);
// 关闭套接字
close(sockfd);
}
int main() {
// 启动 TCP 服务器(单独进程或线程)
pid_t pid = fork();
if (pid == 0) {
tcp_server();
exit(EXIT_SUCCESS);
}
// 客户端执行 TCP 连接和 UDP 通信
sleep(1); // 等待服务器启动
tcp_client();
// UDP 通信(客户端与服务器通信)
udp_communication();
// 等待服务器进程结束
wait(NULL);
printf("All operations completed.\n");
return 0;
}
6.3 多进程、多线程并发服务器设计
多进程并发服务器模型 ⭐
迭代服务器的特点:多用户的情况下,连接建立后,若没有 accept,连接存放在 listen 函数队列。accept 从已完成队列的对头摘取新套接字。对客户端的服务是一个串行的过程
采用多进程的方式引入并行。目的:使得每个客户端都能够得到一个进程的服务
signal函数:使用方法简单,但并不属于 POSIX 标准
函数原型:sig_t signal (int signum, sighandler_t handler)
sigaction 函数:POSIX 标准定义的信号处理接口
函数原型:int sigaction (int signum, const struct sigaction *act, struct sigaction *oldact)
#include <sys/wait.h>
pid_t wait(int *status);
pit_t waitpid(pid_t pid,int *status,int options);
两个函数均为若成功,返回进程ID,若出错则返回-1
多线程
POSIX 线程库——Pthreads 是 POSIX 的线程标准,定义了创建和操纵线程的一套 API。 线程创建 pthread_create( ) 线程等待 pthread_join( ) 获取自己的线程 ID pthread_self( ) 线程分离 pthread_detach( ) 线程终止 pthread_exit() 此外,还有 pthread_kill(), pthread_yield(), pthread_attr_init(), pthread_attr_destroy()等
#include <sys/socket.h>
int shutdown(int sockfd, int how);
功能:可以按照要求关闭连接,且不管有多个文件描述符指向同一个连接,只要调用shutdown去操作了其中某个描述符,连接就会被立即断开。shutdown 可以有选择的终止某个方向的数据传送或者数据传送的两个方向。shutdown直接使得该套接字不可用,而close不能保证(套接字引用计数减为0才关闭)
返回值:成功:返回0,失败:返回-1
6.4 I/O 模型以及基于 I/O 复用的并发服务器设计
POSIX 定义这两个术语如下: 同步 I/O 操作引起请求进程阻塞,知道 I/O 操作完成;异步 I/O 操作不引起请求进程阻塞; IO 的两个阶段都没有被阻塞,才能被称为异步 IO
五种 I/O 模式
① 阻塞 I/O :数据没有到之前程序会一直等待,Linux 下的 I/O 操作默认是阻塞 I/O,即 open 和 socket 创建的 I/O 都是阻塞 I/O
② 非阻塞 I/O:可以通过 fcntl 或者 open 时使用 O_NONBLOCK 参数,将 fd 设置为非阻塞的 I/O。对每次请求,内核都不会阻塞,会立即返回;当没有数据的时候,会返回一个错误
③I/O 多路复用:为了避免 CPU 空转,使用一个代理(select/poll/epoll..)同时观察许多流的 I/O 事件,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中醒来,于是我们的程序就会轮询一遍所有的流。通常需要非阻塞 I/O 配合使用
④ 信号驱动 I/O:信号驱动的 IO 在进程开始的时候注册一个信号处理的回调函数,进程继续执行,当信号发生时,即有了 IO 的时间,这里即有数据到来,利用注册的回调函数将到来的数据用 recvfrom()接收到。
⑤ 异步 I/O:异步 IO 与前面的信号驱动 IO 相似,其区别在于信号驱动 IO 当数据到来的时候,使用信号通知注册的信号处理函数,而异步 IO 则在数据复制完成的时候才发送信号通知注册的信号处理函数
第七章 网安
- 植入恶意软件:病毒、蠕虫、僵尸网络
- 攻击服务器和网络基础设施:拒绝服务攻击(DoS);三种类型:弱点攻击,带宽洪泛,连接洪泛
- 嗅探分组:分组嗅探器:记录每个流经的分组拷贝的被动接收机;容易受到攻击的网络:无线网络和以太网 LAN
- 伪装:将具有虚假源地址的分组注入因特网
- 修改或删除报文:中间人攻击
