1. 网络应用原理

1.1 应用体系结构

应用体系结构(application architecture):由应用程序研发者设计,规定了如何在各种端系统上组织该应用程序

  • 客户-服务器体系结构(client-server):一台主机充当服务器,其他主机充当客户,客户向服务器发送请求,服务器处理这些请求并返回响应

    • 客户之间不直接通信,需要通过服务器
    • 服务器需要同时服务多个客户,常储存在数据中心
  • 对等体系结构(Peer-to-Peer,P2P):所有端点在网络中具有相同的地位,每个端点既可以充当客户也可以充当服务器,称为对等方(peer)

    • 对等方之间可以直接通信,不需要通过专门的服务器
    • 自扩展性(self-scalability):对等方除了是比特的消费者外还是他们的重新分发者

1.2 进程通信

定义:客户是发起通信的进程,服务器是在会话开始时等待联系的进程

套接字(socket):是进程与计算机网络之间的可编程接口,又称为应用编程接口(Application Programming Interface,API)

进程寻址:既要确定主机地址,也需要确定进程地址

  • IP地址(IP address):标识计算机网络中的主机,32位
  • 端口号(port number):标识主机上的进程,16位

1.3 运输服务的性质

  1. 可靠性(reliable):是否确保数据在运输过程中不会丢失、重复或损坏,并且能够被接收方完整地接收到
  2. 吞吐量保证(throughput):发送进程能够向接收进程交付比特的速率的下限
  3. 定时保证:发送方注入套接字的每个比特到达接收方的套接字的时长上限
  4. 安全性:是否对数据进行加密处理

容忍丢失应用:可以接受某些数据到达不了接收进程
带宽敏感应用:具有吞吐量的要求
弹性应用:能够或多或少利用可用带宽
时间敏感应用:具有时延的要求

因特网提供的运输服务

  1. TCP服务

    • 面向连接:先通过握手过程在两个进程的套接字之间建立TCP连接,然后才进行分组传输
    • 可靠传输:确保无差错、按顺序地交付所有发送数据
    • 拥塞控制机制:利用拥塞控制算法来调节数据发送速率,避免网络拥塞
  2. UDP服务

    • 无连接:没有握手过程,无需确认接收方是否准备好
    • 不可靠传输:不保证分组能够到达,也不保证分组的顺序性
    • 没有拥塞控制机制:可以选定任何速率发送

UDP的适用:UDP最显著的优点就是低延迟、高速率和实时性好,最显著的缺点就是丢包和乱序。因此只要应用程序开发者能够很好的设计应用层来自行解决可靠性,UDP就可以最大程度发挥自身优势

1.5 应用层协议

  • 交换的报文类型,如请求报文和响应报文
  • 各种报文类型的语法,如报文中各个字段如何组织
  • 字段的语义,如字段中信息的含义
  • 进程发送和响应报文的规则

2. Web和HTTP

2.1 HTTP概述

万维网(World Wide Web,WWW):一个全球性的、基于因特网的、基于超文本的分布式信息系统

  • Web页面(Web page):由对象组成的文档

    • HTML文件:构建网页的结构和内容
    • CSS文件:构建网页的外观和布局
    • JavaScript文件:构建网页动态效果和互动功能
    • 音乐/图片/视频文件:丰富页面内容
  • Web浏览器(Web browser):作为客户端,负责发起HTTP请求,展示Web网页内容以及处理用户交互

  • Web服务器(Web server):作为服务端,存储Web对象,负责接收HTTP请求,将Web页面返回给浏览器

统一资源定位符(Uniform Resource Locator,URL):用于在Web上标识和访问资源的地址

  • 协议:HTTP或HTTPS,指定了客户和服务器之间通信的协议
  • 主机名:www.example.com,指定了服务器的地址
  • 路径名:/path/to/file,指定了服务器上资源的地址
  • 查询参数(可选):?param1=value1&param2=value2,指定了额外的信息或参数,用于请求特定的数据或定义响应内容
  • 描点/片段标识符(可选):#fragment,指定了Web页面中的特定位置

超文本传输协议(HyperText Transfer Protocol,HTTP):定义了Web浏览器向Web服务器请求Web页面的方式,以及Web服务器向Web浏览器响应Web页面的方式

  • 无状态的(stateless):服务器不存储关于客户的任何状态信息,每个HTTP请求都是独立的,不会受之前请求的影响
  • 客户-服务器应用程序体系结构:浏览器发送请求,服务器处理请求并返回响应
  • 端口号:默认使用80
  • 最广泛版本:HTTP/1.1

2.2 非持续连接和持续连接

往返时间(Round-Trip Time,RTT):分组先从客户到服务器再从服务器返回客户所花费的时间

  • 传播时延:分组在网络中传播所需的时间
  • 处理时延:服务器处理请求并生成响应所需的时间
  • 排队时延:分组在路由器和交换机上的排队等待的时间

非持续连接(non-persistent):每当客户端发起一个请求,就需要与服务器建立一个新的TCP连接,完成请求后,该连接会自动关闭

  • 连接开销大:如果一个Web页面有n个对象,就需要建立n个TCP连接
  • 交付时延:两倍RTT

持续连接(persistent):客户端和服务器可以在同一个TCP连接上发送多个请求和响应

  • 长连接:在请求完成后,连接不会立即关闭,而是保持打开状态,以便未来的请求可以复用这个连接
  • 流水线(pipeline):允许在一个连接上连续发送多个请求,而无需等待前一个请求完成

2.3 HTTP报文格式

请求报文(Request)

  • 请求行
    • 请求方法:声明请求的类型
      • GET:从服务器获取指定资源
      • POST:向服务器提交数据
      • PUT:更新或创建资源
      • HEAD:获取指定资源的元数据,不包括响应体
      • DELETE:请求删除服务器指定资源
      • PATCH:对指定资源进行部分修改
    • 请求目标:指定请求的资源路径
    • HTTP版本:HTTP/1.1或HTTP/2或HTTP/3
  • 首部行/头部行:每行都是一个键值对
    • Host:指示主机名
    • User-Agent:浏览器类型,如Mozilla/5.0
    • Connection:连接类型
    • Accept-Language:语言版本
    • Content-Type:实体体的数据类型
  • 空行:首部行与实体体之间必须存在一个空行
  • 实体体(entity body):用于包含要发送到服务器的数据(GET没有,而POST、PUT、PATCH等具有)
    • 携带用户名和密码,供服务器进行身份验证
    • 携带搜索词,供服务器筛选并生成搜索结果
    • 携带键值对,供服务器进行信息填充
1
2
3
4
5
6
7
8
9
10
11
12
13
PUT /somedir/user HTTP/1.1
Host: www.example.com
Connection: close
User-agent: Mozilla/5.0
Accept-language: en
Content-Type: application/json
Content-Length: 45

{
"name": "Dasi",
"school": "SYSU",
"age": 20
}

响应报文(Response)

  • 状态行
    • HTTP版本:HTTP/1.1或HTTP/2或HTTP/3
    • 状态码和短语
      • 200 OK:请求成功,信息在返回的响应报文中
      • 301 Moved Permanently:请求对象被永久转移了,新的URL在首部行的"Location:"处
      • 304 Not Modified:请求对象未被更改
      • 400 Bad Request:通用差错代码,表示该请求不被服务器理解
      • 404 Not Found:被请求的文档不在服务器上
      • 505 HTTP Version Not Support:服务器不支持请求报文使用的HTTP版本
  • 首部行/头部行:每行都是一个键值对,其中键又称为标头
    • Date:响应报文的生成时间
    • Expires:响应的过期时间
    • Server:服务器类型
    • Connection:连接类型
    • Location:用于重定向的URL
    • Cache-Control:缓存控制指令
    • Content-Type:响应实体的数据类型
  • 空行:首部行与实体体之间必须存在一个空行
  • 实体体(entity body):从服务器获取的数据,如获取Web网页就是获取一个HTML文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HTTP/1.1 200 OK
Connection: close
Date: Fri, 16 Aug 2024 12:00:00 GMT
Server: Apache/2.2.3 (CentOS)
Cache-Control: private, max-age=0
Content-Type: text/html; charset=UTF-8
Content-Length: 138

<!DOCTYPE html>
<html>
<head>
<title>Sample Page</title>
</head>
<body>
<h1>Hello, World!</h1>
<p>This is a sample HTML response.</p>
</body>
</html>

定义:是服务器发送到浏览器并保存在本地的一小块数据,浏览器会存储cookie并在下次向同一服务器发起请求时携带并发送到服务器上,是键值对形式的小型文本文件

三大核心功能

  • 会话状态管理:记录账号密码、登录状态、购物车和游戏分数等用户信息
  • 个性化设置:用户自定义的浏览器偏好设置
  • 行为跟踪:跟踪用户行为,用于分析用户、提供广告或改进服务

工作流程

  1. 服务器设置Cookie:浏览器首次访问服务器时,请求报文中没有Cookie信息,服务器通过Set-Cookie标头在响应中将Cookie发送给浏览器
  2. 浏览器存储Cookie:浏览器接收到Set-Cookie后,将其存储在本地
  3. 客户端发送Cookie:在后续的请求中,浏览器通过Cookie标头在请求中附带信息,以便服务器识别和处理

常见的Cookie值

  • Id:当前用户的Cookie名称
  • expires:指定Cookie的过期时间(绝对时间)
  • max-age:指定了从设置Cookie时间开始的有效时间长度(相对时间)
  • path:指定Cookie的有效路径
  • domain:指定可以访问Cookie的域名
  • secure:指定是否使用HTTPS安全协议发送Cookie
  • HttpOnly: 防止客户端脚本通过document.cookie属性访问Cookie

Cookie的生命周期

  • 会话性(session):没有指定过期时间,在关闭浏览器时会被自动删除
  • 持久性(persistent):Cookie会一直保留在浏览器直到到达过期时间或被手动删除

如果expires是过去的时间,或者max-age是一个小于等于0的数,则浏览器不会存储Cookie
也可以通过修改上述两个值来实现删除Cookie的效果

2.5 Web缓存

Web缓存器(Web cache) / 代理服务器(proxy server):代表初始Web服务器来满足HTTP请求的网络实体,具有自己的磁盘存储空间,保存最近请求过的对象的副本

流程:

  1. 浏览器创建一个到Web缓存器的TCP连接,并向其中对象发送一个HTTP请求报文
  2. Web缓存器检查本地是否存储了对象副本,如有副本则向浏览器发送一个具有该对象的HTTP响应报文
  3. 如Web缓存器没有对象副本,则会创建一个与该对象的初始服务器的TCP连接,然后向初始服务器中的对象发送一个HTTP请求报文
  4. 初始服务器会向该Web缓存器发送一个具有该对象的HTTP响应报文
  5. Web缓存器接收到该对象后,在本地存储空间保存一份副本,并向浏览器发送一个具有该对象的HTTP响应报文

Web缓存器在该流程中既充当客户(向初始服务器请求对象),也充当服务器(给浏览器提供对象)

优点:

  • 大大减少请求的响应时间
  • 减少一个机构的接入链路的通信量,进而无需增大带宽,节约成本
  • 从整体上大大减少因特网上的Web流量,改善所有应用性能

假设浏览器通过局域网接入因特网,则响应时延 = 局域网时延 + 接入时延 + 因特网时延
其中局域网的流量强度为0.2,接入链路的流量强度为0.9,因特网时延为2秒,Web缓存器的命中率为0.4,Web缓存器的访问时间为0.01秒,当流量强度小于0.8时可以忽略不计时延

  • 初始:因为接入链路的流量强度为0.9,则响应时延会变得非常大
  • 方案1:增大接入链路的带宽,使其流量强度降维0.2,则响应时间变为2s
  • 方案2:安装一个Web缓存器,则响应时间变为0.4×0.01s+0.6×2.01s=1.21s

方案2的开销比方案1低得多,而且方案2的效果比方案1还要好得多

条件GET(conditional GET):Web缓存器保存的是初始版本的对象,而在Web服务器上的对象可能已经被更改

  • Last-Modified: date:是服务器向缓存器发送的响应报文中的一个首部行,告知缓存器对象的最后修改日期
  • IF-modified-since: date:是缓存器向服务器发送的请求报文中的一个首部行,告知服务器当且仅当指定日期之后的对象被修改过,才发送该对象
  • 304 Not Modified:是服务器向缓存器发送的响应报文中的状态码和短语,告知缓存器对象未被修改,因此该响应报文中没有包含该对象

2.6 HTTP/2

区别HTTP/1.1HTTP/2
数据格式文本格式二进制格式
多路复用一个TCP连接一次只能处理一个对象一个TCP连接可以同时处理多个对象
首部压缩以明文形式发送使用压缩算法
服务器推客户必须请求每个对象服务器可以主动推送关联对象
响应次序时间次序支持响应报文的优先级,根据请求的重要性优化对象加载顺序

队首阻塞(Head Of Line,HOL):队首请求在遇到延迟或阻塞时,会导致后续的请求无法被处理,直到前面的请求处理完成

  • HTTP/1.1解决:打开多个并行TCP连接,共享可用带宽
  • HTTP/2解决:将每个HTTP报文分成独立的小帧,然后交错发送,并在接收端将它们重新装配起来

3. 电子邮件

3.1 电子邮件系统

组成部分:

  • 用户代理(User Agent,UA):是用户与电子邮件系统的接口,是电子邮件客户端软件
  • 邮件服务器(mail server):用于接收、存储和转发电子邮件和传送电子邮件状况的服务器
  • 简单邮件运输协议(Simple Mail Transfer Protocol,SMTP):用于在网络上发送电子邮件的通信协议
  • 邮箱(mailbox):具有专属的电子邮件地址,其数据存储在邮件服务器,负责管理和维护发送给他的报文

流程:

  1. 发送方编写好电子邮件后,通过用户代理传输电子邮件到发送方的邮件服务器,并放在报文队列中
  2. 发送方的邮件服务器从报文队列中提取该电子邮件,并创建了一个从发送方服务器到接收方服务器的TCP连接
  3. 发送方服务器通过TCP连接发送电子邮件到接收方服务器,接收方的邮件服务器将该电子邮件分发到接收方的邮箱中
  4. 接收方的邮件服务器对接收方的身份进行验证,然后接收方的用户代理从接收方的邮件服务器中读取电子邮件

接收方服务器故障

  1. 发送方的邮件服务器会将该电子邮件放到一个报文队列中,然后周期性尝试发送
  2. 如果在期限内未发送成功,发送方的邮件服务器会删除该报文,并以电子邮件的形式发送到发送方的邮箱来告知电子邮件情况

邮件服务器的特点

  • 当邮件服务器向其他邮件服务器发送电子邮件时,它就表现为SMTP客户
  • 当邮件服务器从其他邮件服务器接收电子邮件时,它就表现为SMTP服务器

3.2 SMTP

直连性:SMTP一般不使用中间邮件服务器来发送或存储邮件,邮件只会存在于发送方服务器和接收方服务器

推拉性:

  • 推协议:SMTP客户建立TCP连接是为了发送文件
  • 拉协议:HTTP客户建立TCP连接是为了接收文件

SMTP握手阶段

  1. 建立连接:客户端通过TCP连接到邮件服务器的端口(默认端口为25,但也可以是587或465,具体取决于是否使用加密),服务器会响应一个以220开头的代码,表示服务器已经准备好接受命令
  2. 开始对话:客户端发送HELO命令表示开始会话,服务器会响应一个以250开头的代码
  3. 认证:客户端发送AUTH LOGIN命令进行认证,服务器会做出响应并要求用户提供用户名和密码
  4. 指定发件人:客户端MAIL FROM:<[email protected]>命令指定邮件的发件人地址,服务器会响应一个以250开头的代码
  5. 指定收件人:客户端RCPT TO:<[email protected]>命令指定邮件的发件人地址,服务器会响应一个以250开头的代码
  6. 开始撰写:客户端发送DATA命令表示将开始发送邮件正文,服务器会响应一个以354开头的代码
  7. 发送报文:客户端发送邮件报文,最后以单独的.结束邮件内容,服务器会响应一个以250开头的代码并排队处理
  8. 结束会话:客户端发送QUIT命令表示会话结束,服务器会响应一个以221开头的代码

邮件报文格式

  1. 首部/头部:包含关于邮件的元数据,如发件人、收件人、主题等,格式是键值对字段,每个字段占据一行
  • From: 发件人地址
  • To: 收件人地址
  • Cc: 抄送地址
  • Bcc: 密送地址
  • Subject: 邮件主题
  • Date: 邮件发送日期
  • Reply-To: 回复地址
  1. 正文:与头部之间隔一个空行,包含邮件的实际内容(纯文本、HTML、附件等),通常使用MIME格式来组织

因特网邮件访问协议(Internet Message Access Protocol,IMAP):允许邮件存储在服务器上,并且客户端可以在多个设备上访问和管理这些邮件

因为SMTP是推协议,因此接收方无法通过SMTP从接收方服务器获取电子邮件

4. DNS

4.1 DNS服务

主机标识的两种方式:主机名(对人友好)和IP地址(对计算机友好)

  • IP地址
    • IPv4地址:由四组数字组成,每组数字范围在0 到255之间,通过.分隔,如192.0.2.172)
    • IPv6地址:由八组十六进制数字组成,每组数字用:分隔如2001:db8:8b73:0000:0000:8a2e:0370:1337
  • 主机名=服务器名+域名
    • 服务器名:指代网络中的某个具体服务
      • www:提供Web网页服务
      • mail:提供电子邮件服务
    • 域名:从左往右级别逐渐升高,每个级别之间用点.分隔
      • 顶级域名:如.cn表示中国,.com表示商业机构,.org表示组织,.gov表示政府机构
      • 主域名:自定义名称
1
2
3
4
5
6
7
8
9
URL: https://www.baidu.com/path/index.html
协议:https
主机名:www.baidu.com
服务器名:www
域名:baidu.com
主域名:baidu
顶级域名:.com
路径:path
对象:index.html

域名系统(Domain Name System,DNS)

  • 实现从主机名到IP地址的映射服务
  • 实现从主机别名(host aliasing)到规范主机名的映射服务
  • 实现从邮件服务器别名(mail server aliasing)到规范主机名的映射服务
  • 负载平衡(load distribution):一个域名可能被冗余分布在多台服务器上,每台服务器都对应一个IP地址,DNS会将同一域名的多个IP地址按照不同排列顺序返回给不同客户端,且客户总是向最靠前的IP地址发送请求,从而分散流量到多个服务器上

如host.dasi.com既提供web服务也提供邮件服务,那么就可以用两个别名www.dasi.com和mail.dasi.com,这样更容易理解和记忆

4.2 DNS工作机理

为什么不只使用一个DNS服务器来负责所有的映射?

  • 单点故障(single point of failure):如果该DNS服务器崩溃,那么整个因特网就崩溃了
  • 通信容量(traffic volume):有数以亿计的DNS查询,不可能造出一个容量这么大的服务器
  • 远距离的集中式数据库(distant centrailized database):DNS服务器无法邻近全部客户,导致严重时延
  • 维护(maintenance):不得不为所有主机保留记录并频繁更新,几乎不可能做到

分布式、层次数据库

服务器类型接收返回
根DNS服务器接收来自客户端或本地DNS服务器的查询请求根据顶级域名返回相应顶级域DNS服务器的IP地址列表
顶级域DNS服务器接收来自根DNS服务器的查询请求根据主域名返回相应权威DNS服务器的IP地址列表
权威DNS服务器接收来自顶级域DNS服务器的查询请求根据主机名返回相应的IP地址
本地DNS服务器接收来自客户端的DNS查询请求返回从缓存或DNS层次结构中获取的IP地址

本地DNS服务器严格上不属于DNS层次结构,它起代理作用,负责将DNS请求转发到DNS服务器的层次结构中

流程:假设客户端要访问www.baidu.com

  1. 客户端首先查询本地DNS服务器缓存
  2. 本地DNS服务器会将请求发送到根DNS服务器,根DNS服务器根据.com返回顶级域DNS服务器的IP地址列表
  3. 本地DNS服务器将请求发送到顶级域DNS服务器,顶级域DNS服务器,顶级域DNS服务器根据baidu.com返回权威DNS服务器的IP地址列表
  4. 本地DNS服务器将请求发送到权威DNS服务器,权威DNS服务器根据www.baidu.com返回主机名的IP地址
  5. 本地DNS服务器获取到IP地址后,返回到客户端并缓存

DNS缓存(caching):会缓存从其他DNS服务器获得的解析结果,减少对上游DNS服务器的请求频率,包括对主机名-IP地址的缓存和对DNS服务器-IP地址的缓存

事实上,绝大部分的DNS查询都绕过了根服务器

4.3 DNS记录

资源记录(Resource Record,RR):提供了主机名到IP地址的映射,是一个包含下列字段的四元组(Name, Value, Type, TTL),其中Name和Value的意义取决于RR类型Type,而TTL(Time To Live)是该记录的生存时间,决定了什么时候从缓存移除

实际上述流程中,服务器并不是返回IP地址列表,而是返回各种不同类型的资源记录

TypeNameValueExample
A主机名IPv4地址(www.baidu.com, 119.75.217.109, A, TTL)
AAAA主机名IPv6地址(www.baidu.com, 2409:8c54:870:34e:0:ff:b024:1916 AAAA, TTL)
NS域名权威DNS服务器的主机名(baidu.com, www.baidu.com, NS, TTL)
CNAME主机别名规范主机名(dasi.com, dasi0227.github.io, CNAME, TTL)
MX邮件服务器别名邮件服务器的规范主机名(qqmail.com, mail.qq.com, MX, TTL)

4.4 DNS报文

DNS只有查询报文和回答报文,且具有相同格式

  • 首部区域:报文的元信息
    • 标识符:唯一标识当前DNS查询报文和DNS响应报文
    • 标志:报文的类型,响应的状态,查询的方式等
    • 问题数:问题区域中问题的数量
    • 回答RR数:回答区域中的RR数量
    • 权威RR数:权威区域中的RR数量
    • 附加RR数:附加信息区域中的RR数量
  • 问题区域:查询的具体信息
  • 回答区域:响应的具体信息
  • 权威区域:提供有关DNS服务器的信息
  • 附加信息区域:提供额外的信息,有助于解析问题

5. P2P

5.1 自扩展性

因特网核心具有足够带宽,瓶颈都在因特网的接入链路

  • 上载(upload):将数据从本地传输到因特网,速率以uu表示
  • 下载(download):将数据从因特网传输到本地,速率以dd表示
  • 分发时间(distribution):所有N个对等方得到文件副本F比特所需要的时间

客户-服务器体系结构:服务器必须向全部对等方都传输一个副本,则一共要上载NF比特

  • 服务器的上载时间:NF/us{NF}/{u_s}
  • 客户的下载时间:F/dc{F}/{d_c}
  • 分发时间:Dcsmax{NF/us,F/dc}D_{cs} \geq max\{NF/u_s,F/d_c\}

P2P体系结构:每个对等方都可以帮助服务器分发副本,因此上载能力等于服务器的上载速率与对等方的上载速率之和

  • 首次服务器上载时间:F/usF/u_s
  • P2P整体的上载时间:NF/(us+uc1+uc2+....+ucN)NF/(u_s+u_{c1}+u_{c2}+....+u_{cN})
  • 对等方的下载时间:F/dcF/d_c
  • 分发时间DP2PmaxF/us,F/dc,NF/(us+uc1+uc2+....+ucN)D_{P2P} \geq max{F/u_s,F/d_c,NF/(u_s+u_{c1}+u_{c2}+....+u_{cN})}

自扩展性:对等方除了是比特的消费者,还是它们的重新分发者

5.2 BitTorrent

术语

  • 洪流(torrent):参与一个特定文件分发的所有对等方的集合
  • 种子(seeder):已经下载了整个文件并留在洪流中继续上载块的对等方
  • 文件块(chunk):洪流中分发的文件被划分为的较小的数据块,通常为256KB
  • 追踪器(tracker):用于协调参与洪流的对等方之间的通信
  • 邻近对等方(neighboring peers):同一洪流中与当前对等方直接相连的其他对等方

流程:

  1. 客户下载.torrent文件加入洪流成为对等方
  2. 追踪器从洪流中随机选取若干个对等方与当前对等方直接相连
  3. 对等方周期性地询问每个邻近对等方所具有的快列表
  4. 对等方向邻近对等方请求它还没有的块
  5. 对等方获得整个文件后,可以离开洪流,也可以留在洪流成为种子

机制

  • 最稀缺优先(rarest first):优先下载邻近对等方中数量最少的块->目的是为了均衡每个块在洪流中的副本数量
  • 一报还一报(tit-for-tat):对等方A会周期性测量从对等方B接收到比特的速率,对等方B也会周期性测量从对等方A接收到比特的速率,如果对等方A和B都满足与此速率,则它们之间保持疏通->目的是对等方能够以趋向于找到彼此协调的速率上载

6. 视频流和CDN

6.1 因特网视频

视频的比特率(bitrate):在视频流中单位时间传输的比特量,衡量了视频的压缩质量即视频的清晰度

  • 空间冗余:相邻的像素通常具有相似的颜色和亮度,因此可以用更少的数据来表示这些相似的像素
  • 时间冗余:相邻帧之间的变化通常很小,因此可以只记录变化的部分而不是每一帧的完整数据

常见的清晰度和比特率关系

清晰度分辨率/px/比特率/Mbps
标清(Standard Definition,SD)720x4801-2.5
高清(High Definition,HD)1280x7202.5-5
全高清 (Full High Definition,Full HD)1920x10805-10
4K超高清(Ultra High Definition,4K UHD)3840x216015-50
8K超高清(Ultra High Definition,8K UHD)7680x432050-100

6.2 DASH

HTTP流(streaming):通过HTTP协议传输和播放多媒体内容的技术

  • 分段传输:媒体内容被分成多个片段,每个片段通过HTTP协议逐段传输
  • 实时播放:浏览器接收到的片段只要超过预先设定的门限,就可以开始播放,而不用等到所有数据都下载完成

经HTTP的动态适应性流(Dynamic Adaptive Streaming over HTTP,DASH):允许客户自由地在视频不同的质量等级之间切换

  • 客户首先请求HTTP服务器获得一份告示文件,其中提供了各个版本视频的URL及其比特率
  • 客户根据可用宽带动态地请求来自不同版本的视频的片段,同时运行一个速率决定算法来选择下次请求的片段

CDN

为什么不建立单一的大规模数据中心来传输流式视频?

  • 若客户远离数据中心,分组将跨越许多通信链路,带来很高的时延
  • 流行的视频可能会经过相同的通信链路发送许多次,浪费了网络带宽,因特网公司不得不付费给ISP运营商
  • 单点故障,即数据中心崩溃会导致任何视频流无法传输

内容分发网(Content Distribution Network,CDN):是一种分布式的网络架构,通过在地理上分散的多个服务器上缓存和分发内容,来实现更快的访问速度和更高的可靠性

CDN的安置原则

  • 深入:在接入ISP中部署CDN集群,目的是靠近端用户,减少端用户和CDN集群之间的链路和路由器数量,从而改善用户感受到的时延和吞吐量
  • 邀请做客:在少量关键位置(如IXP)建造大CDN集群,从而减少维护开销

CDN的流程:假设URL是http://video.baidu.com/movie,使用专用内容分发器网络baiduCDN

  1. 用户的客户端发起一个DNS查询请求,向本地DNS服务器询问video.baidu.com的IP地址
  2. 用户的本地DNS服务器中继DNS请求到baidu的权威服务器
  3. baidu的权威服务器不是直接返回IP地址,而是返回baiduCDN的权威服务器
  4. 用户的本地DNS服务器再一次中继DNS请求到baiduCDN的权威服务器
  5. baiduCDN的权威服务器返回合适的CDN边缘服务器的IP地址
  6. 用户的本地DNS服务器将CDN边缘服务器的IP地址返回给浏览器
  7. 浏览器与CDN边缘服务器建立了一条直连的TCP连接,然后开始传输数据

CDN边缘服务器的选择策略(cluster selection)

  • 地理位置最近(geographically closet):选择距离用户最近的CDN边缘服务器
  • 基于响应时间/网络质量:对时延和丢包率进行周期性地实时测量
  • 负载均衡:选择当前负载较低的CDN边缘服务器

7. 套接字编程

7.1 套接字

套接字(socket):是网络通信的基本接口,是网络协议和应用程序之间的接口,用于在计算机之间的数据交换

  • 协议:TCP/UDP
  • IP地址:通信双方的IP地址
  • 端口号:标识网络上的具体服务

编程函数

  • address:目标地址是一个二元组(host,port)

    • host:IP地址或主机名
    • port:端口号(0-65535)
  • encode(encoding, errors):将str类型转换为bytes类型

    • encoding:编码方式,默认utf-8
    • errors(可选):编码错误的处理方式
  • decode:将bytes类型转换为str类型

    • encoding:解码方式,默认utf-8
    • errors(可选):解码错误的处理方式
  • socket(family, type, proto, fileno):创建套接字

    • family:地址簇,AF_INET用于IPv4,AF_INET6用于IPv6
    • type:类型,SOCK_STREAM用于TCP,SOCK_DGRAM用于UDP
    • proto(可选):特定协议
    • fileno(可选):文件描述符
  • bind(address):将套接字绑定到IP地址和端口号

    • address中的host为’'或0.0.0.0:表示该套接字接受来自任何IP地址的数据
  • connect(address):将客户的套接字连接到服务器

  • listen(backlog):将一个套接字从非连接模式切换到监听模式,准备接受传入的连接请求

    • length:最大等待连接队列长度
  • accept():接受客户端的连接请求

    • 返回值client_socket:一个新的套接字对象,用于与客户端通信
    • 返回值client_address:客户端的地址
  • send(data)/sendto(data, address):发送数据

    • 源地址是系统默认添加到分组中,不需要手动设置
    • data是字节型数据,需要先编码
    • send用于TCP,sendto用于UDP
    • 返回值:实际发送的字节数
  • recv(buffersize)/recvfrom(buffersize):接收数据

    • buffersize:接收缓冲区的大小,以字节为单位
    • recv的返回值:接收到的字节型数据,用于TCP
    • recvfrom的返回值:接收到的字节型数据和发送方的地址,用于UDP
  • close():关闭套接字,释放相关资源

7.2 UDP

客户端发送小写的英文字符串到服务器,服务器将其变为大写字符串后返回给客户端(可以将客户和服务器都设置为本机IP)

clientUDP:

1
2
3
4
5
6
7
8
9
10
11
from socket import *
serverName = '192.168.56.1'
serverPort = 12000
serverAddress = (serverName,serverPort)
print('Server Address:',serverAddress)
clientSocket = socket(AF_INET, SOCK_DGRAM)
message = input('The client send sentence: ')
clientSocket.sendto(message.encode(),serverAddress)
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
print('The client receive sentence:', modifiedMessage.decode())
clientSocket.close()

serverUDP:

1
2
3
4
5
6
7
8
9
10
11
12
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind(('', serverPort))
print("The server is ready to receive")
while True:
message, clientAddress = serverSocket.recvfrom(2048)
print('Client Address:',clientAddress)
print('The server receive sentence:', message.decode())
modifiedMessage = message.decode().upper()
print('The server send sentence:', modifiedMessage)
serverSocket.sendto(modifiedMessage.encode(), clientAddress)

结果

注意要先运行server,再运行client

7.3 TCP

TCP的特殊之处

  • 欢迎套接字(listening socket):位于服务器,用于监听客户端的连接请求,通过函数listen进入监听状态
  • 连接套接字(connection socket):位于服务器,用于与已连接的客户端进行数据交换,通过函数accept创建

客户端发送一个数字到服务器,服务器将其平方后后返回给客户端(可以将客户和服务器都设置为本机IP)

clientTCP:

1
2
3
4
5
6
7
8
9
10
11
12
from socket import *
serverName = '192.168.56.1'
serverPort = 12000
serverAddress = (serverName,serverPort)
print('Server Address:',serverAddress)
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect(serverAddress)
number = input('The client send number: ')
clientSocket.send(number.encode())
modifiedNumber = clientSocket.recv(1024)
print('The client receive number:', modifiedNumber.decode())
clientSocket.close()

clientTCP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from socket import *
serverPort = 12000
listeningSocket = socket(AF_INET, SOCK_STREAM)
listeningSocket.bind(('', serverPort))
listeningSocket.listen(1)
print("The server is ready to receive")
while True:
connectionSocket, clientAddress = listeningSocket.accept()
print('Client Address:',clientAddress)
number = connectionSocket.recv(1024).decode()
print('The server receive number:', number)
modifiedNumber = str(int(number)**2)
print('The server send number:', modifiedNumber)
connectionSocket.send(modifiedNumber.encode())
connectionSocket.close()

结果

注意要先运行server,再运行client