中科大郑烇、杨坚全套《计算机网络(自顶向下方法 第7版,James F.Kuro

### 1.1 什么是Internet
1. 从具体构成角度:由通信链路和节点及协议构成。
- 节点:
- 主机及其上运行的应用程序——主机节点,图形上一般由正方形表示。
- 路由器(网络层)、交换机(数据链路层)等网络交换设备——数据交换节点,图形上一般表示圆形。
- 通信链路:光纤、同轴电缆、无线电、卫星——传输速率:带宽(bps)
- 接入网链路(access):主机连接到互联网的链路(主机节点和数据交换节点之间的链路)
- 主干链路(backbone):路由器间的链路(数据交换节点之间)
- 协议:定义你两个或多个通信实体之间的报文格式和次序,以及在报文传输或接收或其他事件方面所采取的动作。对等层实体通信过程中遵守的规则集合。
- 协议三要素:语法、语义、时序
2. 从服务的角度:
- 分布式的应用
- 为分布式应用提供通信服务的基础设施(应用层以下都属于基础设施,提供形式:API(接口TCP/UDP))
### 1.2 网络边缘(edge):采用网络设施的面向连接服务
- 主机(host/end system)
- 应用程序(客户端和服务器)
- 运行模式:
- c/s模式——>客户/服务器模式(主从模式)
- 客户端向服务器请求、接收服务
- PTP模式——>Peer-Peer(对等模式)
- 目标:在端系统之间传输数据
- 握手:做数据传输之前做好准备(两个通信主机之间为连接建立状态)
- TCP——>传输控制协议(Transmission Control Protocol)——Internet 上面向连接的服务
- 可靠地、按顺序地传输数据——确认和重传
- 流量控制——发送方不会淹没接收方
- 拥塞控制——当网络拥塞时,发送方降低发生速率
- UDP——>用户数据报协议(User Datagram Protocol)
- 无连接
- 不可靠数据传输
- 无流量控制
- 无拥塞控制
### 1.3网络核心
- 网络核心:路由器的网状网络
- 数据通过网络进行传输的方式
- 电路交换(circuit switch)——通常被传统电话网络采用
- 独享资源:不同享——性能保障
- 网络资源被分成片的方式(如带宽)——线路复用
- 频分(Frequency-division-multiplexing)
- 时分(Time-division-multiplexing)
- 波分(Wave-division-multiplexing)——采用光通信
- 码分(CDM)
- 分组交换:以分组为单位储存-转发方式——统计多路复用
- 传输时间使用全部带宽,不再分为一个个片
- 主机之间传输数据被分为一个个分组(packet)
- 排队和延迟——到达速率>链路输出速率
- 路由:决定分组采用的源到目标的路径
- 转发:将分组从路由器输入链路转移到输出链路
- 分组的存储转发一段一段从源端传到目标端,按照有无网络层的连接,分为
- 数据报(datagram):通信之前无须建立连接,有数据就传输,每一个分组都独立路由(路径不同,可能会失序),路由器根据分组的目标地址进行路由。
- 虚电路(virtual circuit)——有连接
- 每个分组都带标签(虚电路标识VC ID),标签决定下一跳
- 做呼叫建立时决定路径,做整个呼叫中路径保持不变
### 1.4 接入网和物理媒体
- 端系统和边缘路由器的连接
- 住宅接入网络:
- modem
- 将上网数据调制(调频/调幅/调相位/综合调制)加载音频信号上,在电话线上传输,在局端将其中的数据解调出来
- 拨号调制解调器56kbps的速率直接介入路由器(通常更低),不能同时上网和打电话:不能总是在线
- 50kbps
- DSL(digital subscriber line)——使用额外带宽
- 采用现存的到交换局DSLAM的电话线
- 如果上下行带宽不对称——IDSL
- 上行——2.5Mbps,下行——24 Mbps
- 线缆网络
- 有线电视信号线缆双向改造
- FDM(频分多路复用):在不同频段传输不同信道道数据,数字电视和上网数据(上下行)
- HFC(hybrid fiber coax—混合光纤同轴电缆):非对称:最高30Mbps下行传输,2Mbps上行传输速率
- 线缆和光纤网络将各个家庭用户接入ISP路由器
- 各用户共享到线缆头端到接入网络,与DSL不同,DSL每个用户一个专用线路到CO(central office)
- 电缆模式
- 电力调制解调器
- FTTH(光纤到户)
- 20Mbps
- 单位接入网络(学校、公司)——Ethernet
- 交换机的集连
- 10Mbps、100Mbps、1Gbps、10Gbps传输速率
- 现在,端系统经常直接连接到以太网络交换机
- 无线接入网络
- 各无线端系统共享无线接入网络(端系统到无线路由器)——通过基站或叫接入点
- 物理媒体
- Bit:在发送-接收对间传播
- 物理链路:连接每个发送-接受对之间的物理媒体
- 导引型媒体:信号沿固体媒介被导引
- 同轴电缆
- 两根同轴的铜导线
- 双向
- 基带电缆——单个频段(信道)工作
- 宽带电缆——多个信道工作
- 双绞线(TP)
- 5类:100Mbps以太网,Gbps千兆以太网
- 6类:10Gbps万兆以太网
- 光纤和光缆
- 光脉冲,每个脉冲表示一个bit,在玻璃纤维中传输
- 高速:点道点道高速传输
- 低误码率:在那个中继器之间可以有很长的距离,不受电磁噪声的干扰
- 安全
- 单模光纤——光信号垂直
- 多模光纤——一定入射角实现全反射
- 非导引型媒体:开放的空间传输电磁波或者光信号,在电磁或者光信号中承载数字数据
- 双向
- 无需物理“线缆”
- 传播环境效应
- 反射
- 吸收
- 干扰
- 地面微波
- LAN
- Wide-area
- 卫星
- 同步静止卫星或低轨卫星
- 270msec端到端延迟
### 1.5 Internet 结构和ISP
- 互联网络结构:网络的网络
- 端系统通过接入ISPs(Internet Service Providers)连接到互联网
- 接入ISPs相应的必须是互联的
- 内容提供商网络(Internet Content Providers)可能会构建它们自己的网络,将它们的服务、内容更加靠近端用户,向用户提供更好的服务,减少自己的运营支出。
- ISP之间的连接
- POP:高层ISP面向客户网络的接入,涉及费用结算
- 对等接入:2个ISP对等互解,不涉及费用结算
- IXP:多个对等ISP互联互通之处,通常不涉及费用结算
- ICP自己部署专用网络,同时和各级ISP连接
### 1.6分组延时、丢失和吞吐量
- 分组延时
- 节点处理延时
- 检查bit级差错
- 检查分组首部和决定将分组导向何处
- 排队延时
- 在输出链路上等待传输的时间,依赖于路由器的拥塞程度
- 流量强度I=La/R——a:单位时间转发分组数量——在0-1之间,设计时不能大于1
- 传输延时
- R=链路带宽(bps)
- L=分组长度(bits)
- 将分组发送到链路上的时间=L/R
- 存储转发延时
- 传播延时
- d=物理链路的长度
- s=在媒体上的传播速度(2\*10^8m/sec)
- 传播延时=d/s
- 分组丢失
- 链路的队列缓冲区容量有限
- 当分组到达一个满的队列是,该分组将会丢失
- 丢失的分组可能会被前一个节点或源端系统重传或根本不重传
- 吞吐量:在源端和目标端之间传输的速率(数据量/单位时间)
- 瞬间吞吐量:在一个时间点的速率
- 平均吞吐量:在一个长时间内的平均值
- 瓶颈链路:端到端路径上,限制端到端吞吐端链路
### 1.7协议层次及服务模型
- 层次化方式实现复杂网络功能
- 将网络复杂的功能分成功能明确的层次,每一个层次实现其中一个或一组功能,功能中有其上层可以使用的功能——>服务
- 协议的功能:本层协议实体相互交互执行本层协议动作,目的是实现本层功能,通过接口为上层提供更好的服务。
- 各协议实体之间是水平关系
- 实现本层协议是,利用了下层所提供的服务
- 本层的服务包括了借助下层提供的服务实现本层协议实体之间交互带来的新功能和下层所提供的服务
- 服务(Service):低层实体向高层实体提供它们之间通信的能力
- 服务用户(Service user)
- 服务提供者(Service provider)
- 原语(primitive):上层区分使用下层服务的形式,高层使用低层提供的服务,以及低层向高层提供服务都是通过服务访问原语来进行交互——形式
- 服务访问点SAP(Service Access Point):使用下层提供的服务通过层间的接口——地点
- 协议和服务关系
- 本层协议的实现依靠下层提供的服务
- 本层协议实体通过协议实现的功能—>为上层提供更好的服务
- 数据单元:
- SDU(Service Data Unit):上层交给下层要传输的数据
- ICI(Interface Control Information):上层SDU穿过层间接口到达下层需添加的信息
- 协议数据单元PDU(Protocol Data Unit):上层SDU+本层ICI——>对等协议实体交换本层PDU
- 层次化优点
- 概念化:结构清晰,便于标示网络组件以及描述相互关系
- 结构化:模块化更易于维护和系统升级
- Internet协议栈
- 应用层:面向用户提供服务——message报文
- FTP,SMTP,HTTP,DNS
- 传输层:在网络层提供端到端通信基础上,细分为进程到进程,将网络层不可靠的服务变成可靠的服务——报文段segment:TCP段,UDP段
- TCP,UDP
- 网络层:在链路层提供服务基础上,传输以分组(packet,如果是无连接的方式:数据报datagram)为单位的端到端的数据传输(选择路由)
- IP(转发),路由协议
- 链路层:在物理层提供服务的基础上,相邻两点(网络节点)之间传输以帧(frame)为单位的数据
- PPP,802.11(wifi)
- 物理层:将数字数据转换为物理信号,物理线路上传送bit(位)
- ISO——国际标准化组织/OSI(开放系统互联open system interconection)参考模型
- 应用层
- 表示层:允许应用解释传输的数据,对数据进行加密,压缩,机器相关的表示转换
- 会话层:数据交换的同步,检查点,恢复
- 传输层
- 网络层
- 链路层
- 物理层
### 2.1 应用层协议原理
- 网络应用体系结构
- cs(客户-服务器模式)
- 服务器
- 一直运行
- 固定ip地址和端口号(例如web80)
- 扩展性差
- 客户端
- 主动与服务器通信
- 与互联网有间歇性连接
- 可能是动态ip地址
- 不直接与其他客户端通信
- 对等模式(peer to peer)
- 任意端系统之间可以进行通信
- 每个节点既是客户端又是服务器
- 才能与端主机间歇性连接且可以改变ip地址导致难以管理
- 没有一直运行的服务器(几乎)
- 混合体:cs和对等体系结构
- Napster
- 即使通信
- 进程通信
- 进程:主机上运行的应用程序
- 客户端进程:发起通信的进程
- 服务器进程:等待连接的进程
- 同一个主机内,使用的是进程间通信机制通信(操作系统定义)
- 不同主机,通过交换报文(message)来通信
- 分布式应用进程通信条件
- 进程标识(SAP)
- 主机ip地址
- 采用传输层协议:TCP/UDP
- 端口号
- \http:TCP80
- Maul:TCP25
- \FTP:TCP21
- 端节点:用于标识一个进程:IP+Port
- 一对主机经常之间的通信由两个端节点构成
- 传输层提供的服务
- 穿过层间接口所需提供信息
- SDU
- 传输源端IP+TCP(UDP)端口号
- 接收端IP+TCP(UDP)端口号
- Socket API:为便于管理,使用一个代号标识双方(TCP)或单方(UDP)——>穿过层间接口信息大小最小
- TCP socket(套接字):4元组(源ip,源port,目标ip,目标port)的一个具有本地意义的标识,可使用这个标识,与远程的应用进程通信
- 如果进程通信之前要建立连接,通信关系稳定,使用一个整数表示两个应用实体之间的**通信关系**,本地标识
- 简单,便于管理(类似于操作系统打开一个文件,os返回一个文件句柄,可以使用这个文件句柄对文件进行操作)
- UDP socket:2元组(源ip,源port)的一个具有本地意义的标识
- 制定了应用所在的一个端节点(end port)
- 发送报文是需指定目标ip和port
- 传输层提供服务基础上实现应用
- 定义应用层协议:运行在不同端系统上的应用经常如何交换报文
- 交换的报文类型:请求和应答报文
- 报文类型的语法:字段及其描述
- 字段的语义
- 进程对发送报文及对报文响应的规则
- 编制程序,通过api调用网络基础设施提供通信服务传报文,解析报文,实现应用时序
- 应用层对传输层所提供服务质量的一些指标
- 数据丢失率
- 延迟
- 吞吐
- 安全性
- 机密性
- 完整性
- 可认证性(鉴别)
- UDP存在的必要性
- 区分不同的进程,ip服务不能
- 无需建立连接
- 不做可靠性工作
- 没有拥塞控制和流量控制,应用能够按照设定的速度发送数据
- SSL——TCP和UDP都没有加密,明文通过互联网传输
- 在TCP上面实现,通过加密的TCP连接
- 私密性
- 数据完整性
- 端到端鉴别
- 在应用层:应用采用SSL库,SSL库使用TCP通信
- SSL socket API:应用通过API将明文交给socket,SSL将其加密在互联网传输
### 2.2 Web 和HTTP
- Web页:由一些对象组成,含有一天基本都HTML文件,该基本HTML文件又包含若干对象的应用(链接URL:访问协议,用户名,口令字,端口等)
- HTTP:超文本传输协议——TCP上——带内传送
- HTTP是无状态:服务器并不维护客户的任何信息
- 非持久HTTP1.0
- 持久HTTP1.1
- 非流水方式——一次只发送一个请求,收到响应后在发送新的请求,每个引用对象花费一个RTT
- 流水方式——HTTP/1.1默认模式,客户端遇到引用对象就产生一个请求,所有引用(小)对象的时间只花费一个RTT是可能的
- 往返时间RTT(round-trip time):一个小的分组从客户端到服务器,然后回到客户端到时间(传输时间忽略)
- 响应时间:2RTT(TCP连接RTT、HTTP请求RTT)+传输时间
- HTTP请求报文:请求(ASCII人能阅读)、响应
- cookies:维护客户端和服务端状态
- 用户验证
- 购物车
- 推荐
- 用户状态
- Web缓存(代理服务器):不访问原始服务器,就满足客户的请求
### 2.3 FTP——有状态协议
- 控制连接(21控制命令的发送)和数据连接(20服务器主动发出)——带外传送(out of band两个连接传送)
### 2.4 EMail
- 用户代理
- 邮件服务器
- 邮箱中管理和维护发送给用户的邮件
- 输出报文队列保持带发送邮件报文
- 邮件服务器之间的SMTP协议:发送email报文
- 简单邮件传输协议:SMTP(发送)25
- 报文必须为7位ASCII码
- 报文格式:多媒体扩展MIME(多媒体邮件扩展)
- 接收方用户代理拉取协议
- POP3——无状态
- 用户确认阶段
- 事物处理阶段
- IMAP
- 相比POP3远程目录维护——状态维护
- HTTP
### 2.5 DNS(Domain Name System)域名解析系统
- DNS协议:查询和响应的报文格式相同
- 必要性:将字符串由DNS转换为二进制网络地址(IP地址:标识主机、路由器)
- 主要思路
- 分层的、基于域的命名机制
- 若干分布式的数据库完成名字到IP地址的转换
- 运行在UDP53端口的应用服务
- 是Internet的核心功能,但以应用层协议实现,运行在网络边缘
- 主要目的
- 实现主机名-iP地址的转换
- 其他目的
- 主机别名到规范名字的转换
- 邮件服务器别名到邮件服务器正规名字的转换
- 负载均衡
- DNS域名结构
- DNS采用层次树状结构的命名方法
- Internet根被划分为几百个顶级域(top lever domains)
- .com、.edu、.gov、.org、.cn、.us、.jp
- 每个(子)域下面可划分为若干个子域
- 树叶是主机
- 名字服务器:维护所管辖区域的权威信息,允许被放置在区域之外,以保障可靠性,为提高性能会进行缓存(TTL:默认两天)
- 区域(zone)
- 顶级域(TLD)服务器:负责顶级域名和所有国家级的顶级域名
- 权威DNS服务器(名字服务器):组织机构的DNS服务器,提供组织机构服务器可访问的主机和IP之间的映射
### 2.6 P2P应用
- 非结构化P2P
- 集中化目录:
- 查询洪泛:Gnutella
- 利用不匀称性:kaZaA
- 结构化(DHT)P2P
### 2.7 视频流化服务和CDN:上下文
- 分布式的,应用层面的基础设施
- CBR(constant bit rate):固定速率编码
- VBR(variable bit rate):视频编码速率随时间的变化而变化
- 存储视频的流化服务:DASH(Dynamic adaptive Streaming over HTTP)
- 将视频文件分为多个块
- 每个块独立存储,编码与不同码率
- 告示文件(manifest file):提供不同块的URL
- CDN(Content Distribute Networks)内容分发网络 over top——网络边缘
- enter deep:将CDN服务器深入到许多本地ISP
- bring home:部署于关键位置POP,采用主要线路将服务器簇连
- 工作原理
- 客户向本地服务器解析请求视频地址Ip返回CDN-URL(重定向),再向CDN-权威DNS服务器解析,选择离客户端最近Cache节点(CDN)IP地址返回,该地址提供流化服务
### TCP套接字编程
- socket:分布式应用进程之间的门,传输层协议提供的端到端之间的服务接口
- sockaddr_in
```c
struct sockaddr_in{
short sin_family; // 地址簇,默认为AF_INET代表TCP/IP协议族
u_short sin_port; // port(使用网络字节顺序)
struct in_addr sin_addr; // sin_addr存储ip地址,使用in_addr这个数据结构
char sin_zero[8]; /* 对齐,为了让sockaddr和sockaddr_in两个数据结构保持大小相同保留的空字节 */
}
```
- hostent(host entry)
- 作为调用域名解析函数时的参数,返回后将IP地址拷贝到sockaddr_id的Ip地址部分
```c
struct hostent{
char *h_name; // 地址的正式名称(域名)
char **h_aliases; // 地址的预备名称指针(别名)
int h_addrtype; // 地址类型,通常为AF_INET
int h_length; // 地址长度
char **h_addr_list; /* 主机网络地址指针,网络字节顺序:占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端 */
# define h_addr h_addr_list[0]; // h_addr_list中第一地址
}
```
- ![[P30808-224451.jpg]]
- ![[Pasted image 20230808224942.png]]
- 例C客户端(TCP)
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main() {
// 创建 socket
int client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 设置服务器地址和端口
struct sockaddr_in server_address;
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8080);
server_address.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器的IP地址
// 连接到服务器
if (connect(client_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == -1) {
perror("Connection failed");
exit(EXIT_FAILURE);
}
// 发送数据到服务器
char message[] = "Hello, server!";
if (send(client_socket, message, strlen(message), 0) == -1) {
perror("Send failed");
exit(EXIT_FAILURE);
}
// 接收服务器的响应
char buffer[1024] = {0};
if (recv(client_socket, buffer, sizeof(buffer), 0) == -1) {
perror("Receive failed");
exit(EXIT_FAILURE);
}
printf("Server response: %s\n", buffer);
// 关闭 socket
close(client_socket);
return 0;
}
```
- 服务器端(TCP)
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main() {
// 创建 socket
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 设置服务器地址和端口
struct sockaddr_in server_address;
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8080); // 使用的端口号
server_address.sin_addr.s_addr = INADDR_ANY; // 使用任意可用的IP地址
// 绑定地址和端口
if (bind(server_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == -1) {
perror("Binding failed");
exit(EXIT_FAILURE);
}
// 监听连接请求
if (listen(server_socket, 5) == -1) {
perror("Listening failed");
exit(EXIT_FAILURE);
}
printf("Waiting for incoming connections...\n");
while (1) {
// 接受连接请求
struct sockaddr_in client_address;
socklen_t client_address_length = sizeof(client_address);
int client_socket = accept(server_socket, (struct sockaddr*)&client_address, &client_address_length);
if (client_socket == -1) {
perror("Accepting connection failed");
continue;
}
printf("Client connected: %s\n", inet_ntoa(client_address.sin_addr));
// 接收客户端发送的数据
char buffer[1024] = {0};
if (recv(client_socket, buffer, sizeof(buffer), 0) == -1) {
perror("Receive failed");
close(client_socket);
continue;
}
printf("Received from client: %s\n", buffer);
// 发送响应给客户端
char response[] = "Hello from server!";
if (send(client_socket, response, strlen(response), 0) == -1) {
perror("Send failed");
}
// 关闭客户端 socket
close(client_socket);
}
// 关闭服务器 socket
close(server_socket);
return 0;
}
```
- UDP套接字编程
- 客户端和服务器之间没有链接
- 传送数据可能失序也可能丢失
- ![[P30809-000646.jpg]]
- ![[Pasted image 20230809000829.png]]
- UDP客户端
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main() {
// 创建 socket
int client_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (client_socket == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 设置服务器地址和端口
struct sockaddr_in server_address;
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8080); // 使用的端口号
server_address.sin_addr.s_addr = INADDR_ANY; // 使用任意可用的IP地址
// 发送数据到服务器
char message[] = "Hello from UDP client!";
if (sendto(client_socket, message, strlen(message), 0, (struct sockaddr*)&server_address, sizeof(server_address)) == -1) {
perror("Sendto failed");
exit(EXIT_FAILURE);
}
printf("Message sent to server: %s\n", message);
// 关闭 socket
close(client_socket);
return 0;
}
```
- UDP服务端
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main() {
// 创建 socket
int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (server_socket == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 设置服务器地址和端口
struct sockaddr_in server_address;
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8080); // 使用的端口号
server_address.sin_addr.s_addr = INADDR_ANY; // 使用任意可用的IP地址
// 绑定 socket 到指定的地址和端口
if (bind(server_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == -1) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
char buffer[1024];
struct sockaddr_in client_address;
socklen_t client_address_length = sizeof(client_address);
// 接收来自客户端的数据
ssize_t bytes_received = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_address, &client_address_length);
if (bytes_received == -1) {
perror("Recvfrom failed");
exit(EXIT_FAILURE);
}
buffer[bytes_received] = '\0';
printf("Message received from client: %s\n", buffer);
// 关闭 socket
close(server_socket);
return 0;
}
```