以下为个人学习笔记和习题整理
课程:哈尔滨工业大学 计算机网络
https://www.bilibili.com/video/BV1Up411Z7hC?share_source=copy_web
网络应用与单机应用的本质不同:
网络应用需要有 网络的基础环境
,一部分软件运行在自己机器上(如浏览器),另一部分软件(或数据信息)运行在互联网的某个地方(如某些服务器),两部分软件需要 进行交互
,才共同构成了网络应用。
既然网络应用是由不同的部分构成的,那么它就存在一个 结构
。
# 网络应用的体系结构
现代网络应用中,有两种主流的体系结构。
# 客户机 / 服务器结构
主从式架构(英语:Client–server model)也称 客户端/服务器架构
、 C/S架构
,是一种网络架构,它把客户端(Client,通常是一个采用图形用户界面的程序),与服务器(Server)区分开来。每一个客户端软件的实例都可以向一个服务器或应用程序服务器发出请求。有很多不同类型的服务器,例如文件服务器、游戏服务器等。
- 服务器 (server)
7 * 24小时
提供服务永久性
访问地址 / 域名- 利用大量服务器实现可扩展性(数据中心,能够处理大量的并发请求)
- 客户端 (client)
- 与服务器通信,使用服务器提供的服务
间歇性
接入网络- 可能使用
动态IP地址
- 不会与其他 “客户机” 直接通信
# 点对点结构
对等式网络(英语:peer-to-peer, 简称 P2P
),又称 点对点技术
,是无中心服务器、依靠用户群(peers)交换信息的互联网体系,它的作用在于,减低以往网路传输中的节点,以降低资料遗失的风险。与有中心服务器的中央网络系统不同,对等网络的每个用户端既是一个节点,也有服务器的功能,任何一个节点无法直接找到其他节点,必须依靠其户群进行信息交流。
- P2P 架构的特点
- 没有永远在线的服务器
- 任意端系统 / 节点之间可以 “直接” 通讯
- 节点间歇性接入网络
- 节点可能改变 IP 地址
# 混合结构(Hybrid)
将两种结构混合在一起使用,利用两者的优点同时规避两者的缺点。如 Napster
。
# 网络应用进程通信
# 进程间通信
进程间通信是网络应用的基础,而 进程
是主机上运行的 程序
,
-
运行在
同一主机上
的进程之间通过由操作系统提供的进程间通信机制
进行通信; -
运行在
不同主机上
的进程之间通过消息交换(报文交换)
进行通信。(★)
# 消息交换的实现
-
Socket 套接字:进程间通信利用
socket
发送 / 接受信息实现(★)。-
可以类比于寄信,socket 套接字接口是
“门”
,而硬件基础设施、网络协议栈(传输层及以下)等是 “门外” 的传输基础设施
,- 发送方将消息送到门外邮箱
- 发送方依赖(门外的)传输基础设施将消息传到接收方所在主机,并送到接收方的门外
- 接收方从门外获取消息
-
操作系统
向进程提供 API(应用编程接口,即套接字 socket) -
应用程序员能控制 socket 应用层端 的所有细节,但对于 socket 传输层端 只有很少的控制,其支持
传输层协议
的选择(TCP 或 UDP)(★)- 可能有的几个
传输层参数
的设置(如最大缓冲区、最大segment
长度)
-
-
进程寻址:实现不同主机上的进程间通信,每个进程必须拥有
标识符
。- 网络层上的
IP地址
,能唯一标识 Internet 上的一台主机; - 操作系统为主机上每个需要通信的进程分配了一个
端口号(Port number)
。
因此,进程的标识符由
IP 地址 + 端口号
组成,能唯一标识一个 “网络上的进程”。 - 网络层上的
-
应用层协议:网络应用需遵循应用层协议,完成消息的具体交换。
网络应用可根据所使用的协议分为两类,公开协议
:由RFC(Request For Comments)
定义,公开的标准、规范,允许互操作。如HTTP
,SMTP
等私有协议
:多数 P2P 文件共享应用
- 应用层协议的内容:(协议三要素)
- 消息的
类型(type)
:如请求消息 / 响应消息? - 消息的
语法(syntax)
:消息中有哪些字段(fields)?每个字段如何描述? - 字段的
语义(semantics)
:字段中信息的含义。 规则(rules)
:进程何时发送 / 响应消息,进程如何发送 / 响应消息。
- 消息的
# 传输层所提供的服务
# 网络应用对传输服务的需求
传输层可提供的服务大致地可分为三类:
可靠数据传输(reliable data transfer)
- 某些网络应用能够容忍一定的数据丢失。
- 网络电话,网络视频
- 某些网络应用要求 100% 可靠的数据传输。
- 文件传输,telnet
- 某些网络应用能够容忍一定的数据丢失。
时间(timing)
- 有些应用只有在延迟足够低时才 “有效”。
- 网络电话,网络游戏
- 有些应用只有在延迟足够低时才 “有效”。
吞吐量(throughput)
- 某些应用只有在带宽达到最低要求时才 “有效”。如网络视频
- 某些应用能够适应任何带宽 ——
弹性应用(elastic)
。如 email,为异步应用,没有太多时间上的要求。
安全性(security)
# Internet 提供的传输服务
- TCP 服务
面向连接
:客户机 / 服务器进程间需要建立连接(全双工)可靠传输
:能够把底层的不可靠转变为可靠。流量控制
:发送方不会发送速度过快,超过接收方的处理能力拥塞控制
:当网络负载过重时能够限制发送方的发送速度(对整个网络起作用)- 不提供时间 / 延迟保障
- 不提供最小带宽保障
- UDP 服务
无连接
不可靠的数据传输
- 不提供:可靠性保障、流量控制、拥塞控制、延迟保障、带宽保障
# Web 应用
# 万维网(World Wide Web)
最基本的构成要素是 网页(Web Page)
,所有的网页之间互相链接。网页包含多个 对象(objects)
,其构成为
对象
:HTML 文件、JPEG 图片、视频文件、动态脚本等,丰富多彩;基本HTML文件
:包含对其他对象引用
的链接,是每个网页都有的。
# HTTP 协议
万维网应用所遵循的协议,称为 超文本传输协议(HyperText Transfer Protocol)
。协议采用的是 客户机/服务器架构
,其
- 客户端:
浏览器(Browser)
,请求、接收、展示 Web 对象; - 服务器:
Web Server
,响应客户的请求,发送对象。
# HTTP 使用的传输层协议:TCP
浏览器 (HTTP 客户端) 与服务器 (HTTP 服务器) 的通信过程:
- 服务器在
80 端口
等待客户的请求 浏览器发起
到服务器的 TCP 连接服务器接受
来自浏览器的 TCP 连接- 浏览器与 Web 服务器交换 HTTP 消息
- 关闭 TCP 连接
# HTTP 连接的两种类型
对 TCP 的两种使用方法:
非持久性连接(Nonpersistent HTTP)
:每个 TCP 连接最多允许传输一个对象
,HTTP 1.0 版本使用非持久性连接。持久性连接(Persistent HTTP)
:每个 TCP 连接允许传输多个对象
,HTTP 1.1 版本默认使用持久性连接。
# 非持久性连接过程
假定用户在浏览器中输入 URL http://www.someschool.edu/someDepartment/home.index
, home.index
包含文本和 10
个 指向 jpeg 图片的链接。
# 响应时间分析与建模
定义 往返时间 RTT (Round Trip Time)
为从客户端发送一个 很小的数据包
到服务器并返回所经历的时间(包括分组的传输时延、排队时延和处理时延)。则从浏览器输入 URL 回车(发送请求)到最后得到文件的 响应时间 (Response time)
包括:
- 发起、建立
TCP 连接
:1 个 RTT 发送 HTTP 请求消息
到 HTTP 响应消息的前几个字节到达
:1 个 RTT- 响应消息中所含的文件 / 对象传输时间
于是,总的响应时间为:
# 非持久性连接的问题
- 每个对象需要
2个RTT
- 理论上,该问题总共需要 个 RTT
- 操作系统需要为每个 TCP 连接
开销资源
(overhead) - 浏览器会打开多个
并行
的 TCP 连接以获取网页所需对象,但这会给服务器带来巨大的负担。
# 持久性连接
发送响应后,服务器保持 TCP 连接的打开,后续的 HTTP 消息可以通过这个连接发送。
按照是否采用 流水机制(pipelining)
,持久性连接可分为:
-
无流水机制
的持久性连接:客户端只有收到前一个响应后才发送新的请求,每个被引用的对象
耗时 1 个 RTT。- 理论上,该问题总共需要 个 RTT
-
带有流水机制
的持久性连接:客户端只要遇到一个引用对象就尽快发出请求,HTTP 1.1 的默认选项。- 理论上,该问题总共需要 个 RTT
# HTTP 的消息格式
HTTP 协议有两类消息: 请求消息
和 响应消息
,均采用 ASCII
码编写,供人类直接阅读。
# 请求消息 (request)
-
Request line
请求行:各版本的method
方法,- HTTP/1.0:
GET
、POST
、HEAD
- HTTP/1.1:除上述三种外,增加了
PUT
和DELETE
- HTTP/1.0:
-
Header lines
头部行 -
Entity body
消息体
# 响应消息 (response)
-
Status line
状态行:status code
响应状态代码。 -
Header lines
头部行
# Cookie 技术:客户端状态信息
HTTP 是无状态协议,但很多应用需要服务器掌握客户端的状态(会话状态,如网上购物)。
- Cookie 的组件(架设在 HTTP 上)
-
HTTP 响应消息的 cookie 头部行
-
HTTP 请求消息的 cookie 头部行
-
保存在客户端主机上的 cookie 文件,由浏览器管理
-
Web 服务器端的后台数据库
-
- Cookie 的原理(通信过程)
服务器端将在客户端初次访问时为其创建 cookie ID(存放在后台数据库),并在返回的响应中增加 Set-cookie 头部行。之后客户端的每次请求中,都带有 cookie 的头部行,服务器收到含有 cookie 头部行的请求,将执行 cookie-specific 即用户特定的动作,以根据客户的状态提供相应的信息。cookie 存储在用户本地终端上,所以一段时间后再次和服务器通信时,服务器仍能读取该客户端的状态。
- Cookie 的作用:身份认证,保留购物车、推荐等用户会话状态信息。
# Web 缓存 / 代理服务器技术
在不访问服务器的前提下满足客户端的 HTTP 请求。
-
客户端使用代理服务器的过程:
- 用户设定浏览器通过
缓存(代理服务器)
进行 Web 访问 - 浏览器向代理服务器发送
所有的HTTP请求
- 如果所请求对象在缓存中(称为
缓存命中
),缓存返回对象 - 否则,缓存服务器向
原始服务器
发送 HTTP 请求,获取对象,然后返回给客户端并保存该对象
- 如果所请求对象在缓存中(称为
- 用户设定浏览器通过
-
性能分析
-
解决同步问题(存放在代理服务器的对象副本可能是陈旧的)
HTTP 协议中的
条件GET (conditional GET)
方法:如果缓存有最新的版本,则不需要发送请求对象- 代理服务器:在 HTTP 请求消息中声明
所持有版本
的日期。If-modified-since: <date>
- 原始服务器:如果缓存的版本是最新的,则响应消息中
不包含对象
。HTTP/1.0 304 Not Modified
- 代理服务器:在 HTTP 请求消息中声明
# Email 应用
# Email 应用的构成组件
-
邮件客户端 (user agent)
- 读、写 Email 消息(网络应用,也有
Web 形式
的客户端,如 QQ-Mail) - 与服务器交互,收、发 Email 消息
- 读、写 Email 消息(网络应用,也有
-
邮件服务器 (Mail server)
-
邮箱
:存储发给该用户的 Email不在线仍然可以发邮件,存储在邮件服务器
-
消息队列(message queue)
:存储等待发送的 Email
-
-
SMTP 协议 (Simple Mail Transfer Protocol)
邮件服务器
之间传递消息所使用的协议(★)- 客户端:发送消息的服务器
- 服务器:接收消息的服务器
# SMTP 协议
使用 TCP
进行 Email 消息的可靠传输(端口 25)
-
传输过程的三个阶段:握手 → 消息的传输 → 关闭
-
命令 / 响应交互模式
-
命令(command)
:ASCII 文本由于历史原因,Email 消息只能包含 7 位
ASCII码
。 -
响应(response)
:状态代码和语句
服务器与客户端交互过程示例:
-
SMTP 协议的特点:
- 使用
持久性连接
(TCP 协议) - 要求消息必须由 7 位
ASCII 码
构成 - SMTP 服务器利用
CRLF.CRLF
确定消息的结束
- 使用
-
STMP 与 HTTP 对比:
- 都使用
命令/ 响应
交互模式 ,命令和状态代码都是 ASCII 码 - HTTP 协议:
拉式(pull)
,把网页 “拉” 回本地;每个对象封装在独立的响应消息中。 - SMTP 协议:
推式(push)
,发出 Email 邮件信息;多个对象在由多个部分构成的消息中发送。
- 都使用
-
# Email 的消息格式
-
SMTP 协议:Email 消息的传输 / 交换协议(RFC 822:文本消息格式标准)
头部行(header)
:To、From、Subject(邮件主题),与 SMTP 命令不同消息体(body)
:消息本身,只能是 ASCII 字符
-
MIME 协议:多媒体邮件扩展(RFC 2045, 2056)
-
通过在邮件头部
增加额外的行
以声明 MIME 的内容类型
-
# 邮件访问协议:从服务器获取邮件
-
POP 协议(无状态协议):
邮局协议(Post Office Protocol)
,是 TCP/IP 协议族中的一员。-
主要用于支持使用客户端远程管理在服务器上的电子邮件。(认证 / 授权和下载,认证过程 → 事务阶段)
-
POP 支持
离线邮件处理
,其具体过程是:邮件发送到服务器上,电子邮件客户端调用邮件客户机程序以连接服务器,并下载所有未阅读的电子邮件。 -
最新版本为
POP3
。
-
-
IMAP 协议(有状态协议):
因特网信息访问协议
(Internet Mail Access Protocol),是一个应用层协议,用来从本地邮件客户端
(如 Microsoft Outlook、Foxmail)访问远程服务器上的邮件。相较于 POP3,更多功能、更加复杂、能够操纵服务器上存储的消息。
- 所有消息统一保存在一个地方:服务器
- 允许用户利用文件夹组织消息
- IMAP 支持跨会话(Session)的用户状态
-
HTTP 协议:浏览器本身也是一种邮件客户端,基于 Web 的 email 应用如 163、QQ Mail 等。
# DNS 服务
# 概述
域名系统(英语:Domain Name System,缩写: DNS
)是互联网的一项服务,它作为将 域名
和 IP 地址
相互映射的一个 分布式数据库
,能够使人更方便地访问互联网。(IP 地址本身是数字,不易于人类使用,而域名相对来说可读性更好)
- DNS 域名解析系统,是由多层命名服务器构成的
分布式数据库
- DNS 本身也是
应用层协议
,由应用层上的软件负责完成名字的解析,- Internet 的核心功能,用应用层协议实现
- 网络边界复杂,分布式而不使用集中式的原因:
集中式存在单点失败问题、流量问题、距离问题和维护性问题,不可伸缩,不适合。
- DNS 提供的服务:
- 域名向 IP 地址的翻译
- 别名服务:主机别名、邮件服务器别名
- 负载均衡:Web 服务器,提供多个映射
# 分布式层次式数据库
客户端想要查询 www.amazon.com
的 IP 地址:
- 客户端查询
根服务器
,找到 com 域名解析服务器 - 客户端查询
com 域名解析服务器
,找到 amazon.com 域名解析服务器 - 客户端查询
amazon.com 域名解析服务器
,获得 www.amazon.com 的 IP 地址
-
根域名服务器 (Root DNS servers)
本地域名解析服务器
无法解析域名时,访问根域名服务器
。- 根域名服务器如果不知道映射,则访问权威域名服务器获得映射,再向本地域名服务器返回映射。
-
顶级域名服务器 TLD (Top-Level Domain)
负责com
、org
、net
、edu
等顶级域名和cn, uk, fr
等国家顶级域名Network Solutions
维护 com 顶级域名服务器Educause
维护 edu 顶级域名服务器
-
权威 (Authoritative) 域名服务器:组织的域名解析服务器,提供组织内部服务器 (本地化,自治) 的解析服务。
- 组织自己负责维护,或委托
- 服务提供商负责维护
-
本地域名解析服务器(
不严格属于
层级体系)- 由 ISP 提供,每个 ISP 都有一个本地域名服务器,又称默认域名解析服务器
- 当主机进行 DNS 查询时,查询被发送到本地域名服务器,作为代理将查询转发给 (层级式) 域名解析服务器系统,或利用缓存
# DNS 查询
存在两种查询方式:
-
迭代查询:被查询服务器返回域名解析服务器的名字
-
递归查询:将域名解析的任务交给所联系的服务器
# DNS 记录缓存和更新
只要域名解析服务器获得 域名-IP 映射
,即 缓存
这一映射
- 一段时间过后,缓存条目失效(删除)
本地域名服务器
一般会缓存顶级域名服务器的映射,因此根域名服务器不经常被访问
。
# DNS 记录和消息格式
-
资源记录 (RR, resource records):
RR format: (name, value, type, ttl)
不同的类型对
name
和value
的解释不同:Type 解释 Name Value A 最基本的主机到 IP 地址的映射 主机域名 IP 地址 NS 权威域名解析服务器 域(如 edu.cn) 该域权威域名解析服务器的主机域名 CNAME 实现别名服务 某一真实域名的别名 Value:真实域名 MX 邮件服务器 与 name 相对应的邮件服务器 -
消息格式
- DNS 协议:
查询/回复
模式,查询(query)和回复(reply)的消息格式相同
- 消息头部
-
Identification
:16 位查询编号,回复使用相同的编号 -
flags
:查询或回复、期望递归、递归可用、权威回答
-
- DNS 协议:
# P2P 应用
# 文件分发场景
C/S 架构
v.s. P2P 架构
:从一个服务器向 N 个节点分发一个文件需要多长时间?
-
C/S 架构
:服务器串行地
发送 N 个副本- 完成文件分发所需的时间:
-
P2P 架构
:服务器必须发送一个副本。而拥有该文件的一部分的结点可以共同协助
将文件上传到 Internet 上。- 完成文件分发所需的时间:
# 索引技术
P2P 系统的索引,即 信息
到 节点位置(IP地址+端口号)
的映射。
-
集中式索引
:内容和文件传输是分布式的,但是内容定位是高度集中式的(由一台中央目录服务器负责索引)。存在的问题:单点失效问题、性能瓶颈、版权问题
-
洪泛式查询(Query flooding)
:完全分布式架构,每个节点对它共享的文件进行索引,且只对它共享的文件进行索引。-
覆盖网络 (overlay network): Graph
- 节点 X 与 Y 之间如果有 TCP 连接,那么构成一个边(虚拟链路)
- 所有的活动节点和边构成覆盖网络。
查询消息通过已有的 TCP 连接发送,节点转发查询消息。
如果查询命中,则利用反向路径发回查询节点,最后请求查询的主机和命中主机建立 TCP 连接。
-
-
层次式覆盖网络
:介于集中式索引和洪泛查询之间的方法- 每个节点或者是一个
超级节点
,或者被分配一个超级节点(普通结点),超级节点负责跟踪子节点的内容(提供索引)- 节点和超级节点间维持 TCP 连接(分层式)
- 某些超级节点对之间维持 TCP 连接(洪泛式、分布式)
- 每个节点或者是一个
# socket 编程
socket 是一种 操作系统
提供的 进程间通信机制
在操作系统中,通常会为 应用程序
提供一组 应用程序接口(API)
,称为套接字接口(英语:socket API)。
- 最初设计:socket API 来源于 Unix-Berkley 的项目,是面向 TCP/IP 协议栈的接口(当前可以面向多个协议栈)。
- 目前:事实上的工业标准,绝大多数 OS 均支持,是 Internet 网络应用最典型的 API 接口。
- 通信模型:客户机 / 服务器模型(C/S),是应用进程间通信的抽象机制。
# 应用编程接口 API
应用进程的控制权和操作系统的控制权进行转换的一个 系统调用
接口。
-
应用进程将
控制权
交给操作系统(系统调用),操作系统执行相应的过程,并将结果返回给应用进程。
# 三种典型的 API
-
Berkeley
UNIX 操作系统
定义的一种 API,称为套接字接口(socket interface),简称套接字(socket)。最具有代表性,应用最广泛的标准的伯克利套接字。
-
微软在 socket 的基础上扩展形成的一个稍有不同的 API,称为
WINSOCK
(Windows Socket Interface)。Unix / Linux
使用的是标准的伯克利套接字,而windows
使用的是WINSOCK
,两者之间有很大部分重叠。 -
AT&T
为其UNIX V
定义了一种 API,简写为TLI
(Transport Layer Interface)传输层接口。
# 应用进程通信的寻址问题
- 标识通信端点(对外)
IP 地址 + 端口号
(又称 “端点地址”)
- 操作系统如何管理套接字(对内)
- 套接字描述符 (socket descriptor):小整数
- socket 抽象:当应用进程
创建套接字
时,操作系统分配一个数据结构
存储该套接字相关信息,并返回套接字描述符
# socket API 函数
函数名 | 函数功能 | 适用条件 |
---|---|---|
WSAStartup() |
初始化 socket 库 | 仅对 WinSock |
WSACleanup() |
清除 / 终止 socket 库的使用 | 仅对 WinSock |
socket() |
创建套接字 | |
closesocket() |
释放 / 关闭套接字 | 在 Unix / Linux 中为 close() ,与关闭文件相同 |
bind() |
绑定套接字的本地 IP 地址和端口号 | 通常客户端不需要,由操作系统自动完成 |
listen() |
置服务器端 TCP 套接字为监听模式,并设置队列大小 | 仅用于服务器端 TCP 套接字 |
connect() |
“连接” 远端服务器(UDP 实际上没有连接) | 仅用于客户端 |
accept() |
接受 / 提取一个 TCP 连接请求,创建新套接字,通过新套接字通信 | 仅用于服务器端 TCP 套接字 |
send() |
发送数据 | 用于 TCP 套接字 或 连接模式的客户端 UDP 套接字 |
sendto() |
发送数据报 | 用于非连接模式的 UDP 套接字 |
recv() |
接收数据 | 用于 TCP 套接字 或 连接模式的客户端 UDP 套接字 |
recvfrom() |
接收数据报 | 用于非连接模式的 UDP 套接字 |
setsockopt() |
设置套接字选项参数 | |
getsockopt() |
获取套接字选项参数 |
# socket 编程示例
# Socket Programming with UDP
-
The client-server application using
UDP
:# UDPClient.py
from socket import *
serverName = 'hostname'
serverPort = 12000
clientSocket = socket(AF_INET, SOCK_DGRAM)
message = input('Input lowercase sentence:')
clientSocket.sendto(message.encode(), (serverName, serverPort))
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
print(modifiedMessage.decode())
clientSocket.close()
# UDPServer.py
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)
modifiedMessage = message.decode().upper()
serverSocket.sendto(modifiedMessage.encode(), clientAddress)
# Socket Programming with TCP
-
TCP Server
欢迎套接字(welcome socket)
与连接套接字(connection socket)
: -
The client-server application using
TCP
:# TCPClient.py
from socket import *
serverName = 'servername'
serverPort = 12000
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName,serverPort))
sentence = input('Input lowercase sentence:')
clientSocket.send(sentence.encode())
modifiedSentence = clientSocket.recv(1024)
print('From Server: ', modifiedSentence.decode())
clientSocket.close()
# TCPServer.py
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET,SOCK_STREAM)
serverSocket.bind(('',serverPort))
serverSocket.listen(1)
print('The server is ready to receive')
while True:
connectionSocket, addr = serverSocket.accept()
sentence = connectionSocket.recv(1024).decode()
capitalizedSentence = sentence.upper()
connectionSocket.send(capitalizedSentence.encode())
connectionSocket.close()