应用层协议是为了解决某一类应用的问题。由于网络应用的多样性,应用层的协议也种类繁多。
应用层的许多协议都是基于客户/服务器方式,其描述的是进程之间服务和被服务的关系。客户 (client) 和服务器 (server) 都是指通信中所涉及的两个应用进程。
这里主要的特征是:客户是服务请求方,而服务器则是服务提供方。
套接字编程接口
套接字 (socket) 是最常用的应用层编程接口。网络子系统作为操作系统的一部分,以应用编程接口 (Application Programming Interface, API) 的形式向应用程序提供调用接口。
经典的 socket 编程接口采用同步调用方式,又称阻塞式。这是因为调用 recv() 时,调用进程将被阻塞,直到收到数据为止。
而 Windows 这类基于事件驱动的系统中,程序的执行由事件驱动,需要异步事件驱动方式的套接字编程接口。因此 Microsoft 推出了 WinSock 编程接口,在阻塞式调用基础上,增加了异步调用方式。在阻塞式调用模式上,WinSock 与经典的 socket 兼容。
常见的 socket 接口函数
创建一个socket
SOCKET socket ( int af, int type, int protocol )
将本地地址与 socket 绑定
int bind ( SOCKET s, struct sockaddr *name, int namelen )
在套接字上舰艇连接请求
int listen ( SOCKET s, int backlog )
与 name 指定的地址建立连接
int conect ( SOCKET s, struct sockaddr *name, int namelen )
接受与本 socket 的连接请求
SOCKET accept ( SOCKET s, struct sockaddr *addr, int *addrlen )
在连接的 socket 上发送数据
int send ( SOCKET s, char* buf, int len, int flags )
在连接的活绑定的 socket 上接收数据
int recv ( SOCKET s, char* buf, int len, int flags )
向指定的目标地址发送数据
int sendto ( SOCKET s, char* buf, int len, int flags, struct sockaddr *to, int tolen )
在 socket 上接收数据并记录源地址
int recvfrom ( SOCKET s, char* buf, int len, int flags, struct sockaddr *from, int* fromlen )
域名系统 DNS
域名系统 (Domain Name System, DNS) 是 Internet 使用的命名系统。其基于 UDP 协议实现。
当应用程序需要进行域名解析时,调用域名解析程序 (resolver),即成为 DNS 的一个客户。
该程序会向本地域名服务器发送域名解析请求 (UDP 报文),其中包含待解析的域名。
本地域名服务器在查找域名后,会返回应答报文,其中包含对应的 IP 地址。
Internet 的域名结构
Internet 采用层次结构的命名树作为主机的名字,并使用分布式的域名系统 DNS。
域名不区分大小写,且长度不超过 255 字符。其层次树状结构的命名方法为:
… . 三级域名 . 二级域名 . 顶级域名。
顶级域名 (Top Level Domain, TLD)
顶级域名可分为国家顶级域名以及通用顶级域名。
国家顶级域名,如 .cn 表示中国、.us 表示美国、.uk 表示英国等。
通用顶级域名,如 .com 表示公司和企业、.net 表示网络服务机构、.org 表示非盈利性组织以及 .edu 表示教育机构等。
域名服务器
多个域名服务器上运行专门的域名服务器程序,以完成域名到 IP 地址的解析 (resolve)。
域名服务器会定期把数据复制到几个域名服务器来保存,其中一个是主域名服务器,其他的则是辅助域名服务器。
域名服务器分为四类:
根域名服务器
根域名服务器知道所有的顶级域名服务器的域名和 IP 地址。
当本地域名服务器无法解析域名时,就会求助于根域名服务器。
顶级域名服务器
负责管理在该顶级域名服务器注册的所有二级域名。
权限域名服务器
负责一个区 (zone) 的域名服务器。
本地域名服务器
也称为默认域名服务器。
域名解析过程
域名服务器的监听端口号为 53。为了提高域名查询的效率,域名服务器上通常会设置高速缓存。
主机向本地域名服务器的查询一般采用递归查询。如果本地域名服务器不知道被查询域名的 IP 地址,就会以 DNS 客户的身份,向根域名服务器继续发出查询请求报文。
递归查询是一个接一个往下问,查询到后再一个接一个返回结果。
本地域名服务器向根域名服务器的查询通常是采用迭代查询。当根域名服务器收到本地域名服务器的迭代查询请求报文时,要不就给出所要查询的 IP 地址,否则就告诉本地域名服务器下一步应该向哪一个域名服务器查询,让本地域名服务器进行后续的查询。
迭代查询是一个服务器对多个服务器进行轮询。
文件传送协议
文件传送协议 (File Transfer Protocol, FTP) 使用客户/服务器方式,一个 FTP 服务器进程可以同时为多个客户进程提供服务。
FTP 的服务器进程由两大部分组成,一个负责接收新请求的主进程以及若干个负责处理单个请求的从属进程。
主进程的工作步骤
- 打开熟知端口 (端口号为 21),使客户进程能连接上
- 等待客户进程发出连接请求
- 启动从属进程处理客户进程发来的请求。从属进程在处理完客户进程的请求后就会终止,运行期间还可能会根据需要创建其他子进程
- 回到等待状态,继续接收其他客户进程发来的请求
- 主进程与从属进程的处理是并发进行的
TCP 连接
FTP 使用 2 个 TCP 连接,控制连接和数据连接
控制连接
控制连接会在整个会话期间一直保持打开。
FTP 客户发出的传送请求通过控制连接发送给服务器端的控制进程,但控制连接不用来传送文件。
数据连接
收到 FTP 客户发送来的文件传输请求后,服务器端的控制进程创建数据传送进程和数据连接。
数据传送进程实际完成文件的传送,传送完毕后关闭数据传送链接,并结束运行。
万维网 WWW
WWW 为 World Wide Web 的缩写,是分布式超媒体 (hypermedia) 系统,它是超文本 (hypertext) 系统的扩充。
统一资源定位符 URL
URL 的全称为 Uniform Resource Locator,是对 Internet 上资源位置和访问方法的一种简洁表示,用以标识分布在整个因特网上的万维网文档。
URL不区分大小写,其一般形式为:协议://主机:端口/路径。
主机
存放资源的主机在 Internet 中的域名
端口 和 路径
有时可省略。使用 http 协议时,省略端口将使用熟知端口号 80,省略路径F则指向主页 (home page)。
超文本传输协议 HTTP
HTTP 的全称为 HyperText Transfer Protocol,其基于 TCP 协议,是万维网上可靠地交换文件的重要基础,用以实现万维网上各种超链的链接。
HTTP 是面向事务的客户/服务器协议,是无状态的,即服务器不记录客户端的访问状态。
其基本工作原理为:
- Web 服务的熟知端口号为 80,服务器通常在该端口上监听。
- 客户端需要请求某个页面时,与服务器建立 TCP 连接。
- 之后请求传送文件,并进行文件的传送。
- 传送完毕后释放 TCP 连接。
报文类型
HTTP 的报文类型可分为请求报文以及响应报文。请求报文是从客户向服务器发送请求报文,而响应报文则是从服务器到客户的回答。由于 HTTP 是面向正文的 (text-oriented),报文中的字段都是 ASCII 码串,因此每个字段的长度都是不确定的。
HTTP 应答报文的开始行是状态行,其包括三项内容:HTTP 的版本、状态码以及解释状态码的简单短语。
HTTP/1.0
HTTP/1.0 请求一个万维网文档所需的步骤与时间:
- 首先建立 TCP 连接,需 3 次握手。
- 在 2 次握手后,第 3 次握手报文的数据部分可传送 HTTP 请求报文。
因此请求文档所需时间为:文档传输时间 + 2 倍 RTT 时间。
由于每传送一个文件都需要建立一次 TCP 连接,而一个 Web 页面常常包含数量众多的文件,导致效率过低。 因此有了 HTTP/1.1 的改进。
HTTP/1.1
HTTP/1.1 协议使用持续连接 (persistent connection)。
服务器发送响应后,会在一段时间内保持连接,使客户与服务器可以继续传送后续的 HTTP 请求报文和响应报文。这并不局限于传送同一个页面上链接的文档,而是只要这些文档都在同一个服务器上即可。
目前主流的浏览器都默认支持 HTTP/1.1。
超文本标记语言 HTML
HTML 的全称为 HyperText Markup Language,用以存储和表示万维网文档。
RFC 1866 为 HyperText Markup Language - 2.0。
HTML 定义了许多用于排版的命令,即标签 (tag)。
HTML 把各种标签嵌入到万维网的页面中,构成 HTML 文档。浏览器从服务器读取 HTML 文档后,按照其中嵌入的各种标签,根据显示器尺寸和分辨率显示页面。
仅当 HTML 文档是以 html 或 htm 为后缀时,浏览器才会对此文档的各种标签进行解释
安全的 HTTP 协议:HTTPS
HTTPS 是安全的 HTTP 协议,其建立在 SSL 基础上。其熟知端口号为 443,而不是 80。
SSL 的全称为 Secure Socket Layer,为 TCP 协议提供信息加密和完整性。
NetScape 于 1994 年开发,1996 年发布 SSL 3.0,1999 年 IETF 在 SSL 3.0 的基础上推出了 TLS (Transport Layer Security)。
SSL/TLS 已被浏览器广泛支持,很多 Web 应用利用 HTTPS 协议实现安全传输。
SSL会话的建立过程如下:
- 浏览器 A 将其支持的加密算法告知服务器 B
- 服务器 B 将自己所支持的加密算法与浏览器所支持的加密算法进行交集,再选定一种加密算法
- 服务器 B 以数字证书的方式将自己的公钥传送给浏览器 A
- 浏览器 A 鉴别服务器 B 的证书后,从中取得公钥
- 浏览器 A 产生秘密数,并使用此秘密数产生会话密钥。随后将密钥发送给服务器 B
- 服务器 B 也使用此秘密数产生会话密钥。
- 到此完成 SSL 会话建立,使用会话密钥加密,开始数据传输
电子邮件
电子邮件系统的两种实体为用户代理以及邮件服务器。
用户代理 (User Agent, UA)
用户代理是用户与电子邮件系统的接口,即电子邮件客户端软件。
其功能有撰写、显示、处理和通信。
邮件服务器
邮件服务器用于发送和接收邮件,并向发送人报告传送信息,如已交付、被拒绝或丢失等。
邮件服务器按照客户/服务器方式工作,即一个邮件服务器可以作为客户,也可以作为服务器。
邮件服务器发送邮件使用 SMTP 协议,而客户端读取邮件则使用 POP3 协议。
简单邮件传送协议 SMTP
SMTP 为发送邮件的协议,其全称为 Simple Mail Transfer Protocol。
RFC 2821 (前为 RFC 821):Simple Mail Transfer Protocol
SMTP 规定了两个相互通信的 SMTP 进程之间应该如何交换信息。
SMTP 使用客户/服务器的方式工作,负责发送邮件的 SMTP 进程为 SMTP 客户,而负责接收邮件的 SMTP 进程为 STMP 服务器。
SMTP 定义了 14 条命令和 21 种应答信息。每条命令用 4 个字母组成,而每一种应答信息则一般只有一行信息,由一个 3 位数字的代码开始,后面可视情况附上简单的文字说明。
SMTP 通信的三个阶段为连接建立、邮件传送以及连接释放。
连接建立
连接在发送主机的 SMTP 客户和接收主机的 SMTP 服务器之间建立,不使用中间邮件服务器。
连接释放
邮件发送完毕后,SMTP 释放 TCP 连接。
电子邮件的信息格式
RFC 2822 (前为 RFC 822):Internet Message Format
一个电子邮件分为信封和内容两大部分。
RFC 822 只规定了邮件内容中的首部格式,而邮体的主体部分则由用户自由撰写。
首部中的主要字段如下:
- To:后面填入一个或多个收件人的 e-mail 地址
- Subject:邮件的主题,反映了邮件的主要内容
- Cc:抄送,表示给某人发送一个邮体副本
- From:发信人的电子邮件地址
- Date:发信日期
- Reply-to:对方回信地址
MIME
早期的邮件仅支持 7bit ASCII 编码,导致传送非英语信息时存在困难。因此 1993 年提出了 MIME 标准。
MIME 的全称为 Multi-purpose Internet Mail Extension。
MIME 标准通过在邮件首部中说明数据类型,如文本、声音、图像、视像等,可在邮件传送多种类型的数据。
读取邮件的协议为 Post Office Protocol, POP3 和 Internet Message Access Protocol, IMAP。
MIME 的思路如下:
- 继续使用目前的 RFC 822 格式
- 对二进制数据进行编码,将其转换为 7 位 ASCII 码
- 邮件首部中增加字段,定义数据类型和编码规则
MIME 新增的 5 种头部字段如下:
- MIME-Version:MIME 版本号,一般为 1.0
- Content-Type:报文体中数据的类型
- Content-Transfer-Encoding:传输时编码格式
- Content-ID:唯一的标识符
- Content-Description:供人阅读的内容描述
传统的编码规则有:
- base64:又称为基数 64 转换 (Radix-64),原始二进制数据中的每 6bit 被映射为 8bit,即 ASCII 字符。
- quoted-printable:原始二进制数据的 8bit 表示为 2 个 16 进制数,并前加 = 符号。