根据《计算机网络自顶向下方法》一书总结计算机网络中的常见协议和服务
应用层
HTTP协议
HTTP协议又称为超文本传输协议,是WEB应用的核心。
连接过程
HTTP协议基于TCP实现,是一个 client-server协议,客户端一般指浏览器,服务端一般为远程WEB服务器,一个典型的 HTTP 会话如下:
- 客户端建立一条 TCP 连接
- 客户端发送请求
- 服务器处理请求并送回应答,回应包括一个状态码和对应的数据。
注意:从 HTTP/1.1 开始,连接在完成第三阶段后不再关闭,客户端可以再次发起新的请求。这意味着第二步和第三步可以连续进行数次。
HTTP/1.0 默认为每一对 HTTP 请求/响应都打开一个单独的 TCP 连接。当需要连续发起多个请求时,这种模式比多个请求共享同一个 TCP 链接更低效。为了减轻这些缺陷,HTTP/1.1 引入了流水线(被证明难以实现)和持久连接的概念:底层的 TCP 连接可以通过Connection头部来被部分控制。
HTTP 是无状态,有会话的
在同一个HTTP连接中,两个执行成功的请求之间是没有关系的。HTTP并不保存客户信息,所以不能记录状态。但是我们平时登录状态等是怎么实现的呢?
这是使用了HTTP的头部扩展——HTTP Cookies 解决的这个问题。把 Cookies 添加到头部中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态
总结来说就是HTTP 本质是无状态的,使用 Cookies 可以创建有状态的会话
。
HTTP请求类型
HTTP共八种请求类型:
OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法。也可利用向Web服务器发送’*’的请求来测试服务器的功能性。
HEAD:向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。
GET:向特定的资源发出请求。
POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的创建和/或已有资源的修改。
PUT:向指定资源位置上传其最新内容。
DELETE:请求服务器删除Request-URI所标识的资源。
TRACE:回显服务器收到的请求,主要用于测试或诊断。
CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
其中最常用的是GET
和POST
请求:
GET方法请求一个指定资源的表示形式,使用GET的请求应该只被用于获取数据.
POST方法用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用。
两者对比如下:
\ | GET | POST |
---|---|---|
后退按钮/刷新 | 无害 | 数据会被重新提交 |
缓存 | 能被缓存 | 不能缓存 |
编码类型 | application/x-www-form-urlencoded | application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。 |
历史 | 参数保留在浏览器历史中。 | 参数不会保存在浏览器历史中。 |
对数据长度的限制 | 当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。 | 无限制 |
数据类型 | 只允许 ASCII 字符 | 没有限制 |
安全性 | GET 的安全性较差,因为所发送的数据是 URL 的一部分 | POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。 |
可见性 | 数据在 URL 中对所有人都是可见的。 | 数据不会显示在 URL 中 |
关于HTTP更多的信息可以参考,HTTP|MDN
SMTP协议
SMTP(simple Mail Transfer Protocol)简单邮件协议,也是使用TCP进行可靠的数据传输。与HTTP不同的是,SMTP为一个
push protocol
发送邮件服务器把文件推向接受服务器,而HTTP为一个pull protocol
DNS服务
DNS(Domain Name System)提供域名到IP地址的转换。是一个由分层的 DNS 服务器(DNS server)实现的分布式数据库,也是一个使得主机能够查询分布式数据库的应用层协议。
DNS运行于53端口上,基于UDP
协议实现。
这里其实不够严谨,应该说主要使用UDP、其实也是可以使用TCP的。查了一些资料,总结一下使用UDP的原因:
- DNS传输的数据包较小,UDP一次就能解决。当然DNS也有规定当数据包超出大小限制而被截断时会尝试使用TCP进行重试。
- TCP的时间开销大,在设计之初在性能和稳定性上选择了性能。
- 设计时未考虑安全问题(认为没人去伪造DNS报文),所以现在已经有了使用TCP的DNS和DoH(DNS over HTTPS)来进行域名解析了。
参考资料:为什么 DNS 使用 UDP 协议
DNS 不是一个直接和用户打交道的应用。DNS 是为因特网上的用户应用程序以及其他软件提供一种核心功能。主要为其他应用层协议提供服务。
比如浏览器请求一个域名资源的过程:
- 同一台用户主机上运行着 DNS 应用的客户端
- 浏览器从上述 URL 中抽取出主机名 www.someschool.edu ,并将这台主机名传给 DNS 应用的客户端
- DNS 客户向 DNS 服务器发送一个包含主机名的请求。
- DNS 客户最终会收到一份回答报文,其中包含该目标主机的 IP 地址
- 一旦浏览器收到目标主机的 IP 地址后,它就能够向位于该 IP 地址 80 端口的 HTTP 服务器进程发起一个 TCP 连接。
由于单一服务器容易出现故障且存储数据过大、远距离访问困难等问题。现代DNS被设计成了分布式、层次化
的结构。
大致来说有三种 DNS 服务器:根DNS服务器、顶级域(Top-Level Domain, TLD) DNS服务器 和权威DNS服务器 。这些服务器的层次模型如下图所示:
这种结构下的查询过程如下:
- 用户在浏览器中输入网址 www.example.com 并点击回车后,查询会进入网络,并且由 DNS 解析器进行接收。
- DNS 解析器会向根域名发起查询请求,要求返回顶级域名的地址。
- 根 DNS 服务器会注意到请求地址的前缀并向 DNS 解析器返回com的顶级域名服务器(TLD) 的 IP 地址列表。
- DNS 解析器会向 TLD 服务器发送查询报文
- TLD 服务器接收请求后,会根据域名的地址把权威 DNS 服务器的 IP 地址返回给 DNS 解析器。
- DNS 解析器将查询直接发送到权威 DNS 服务器
- 权威 DNS 服务器将 IP 地址返回给 DNS 解析器
- DNS 解析器将会使用 IP 地址响应 Web 浏览器
DNS的两种查询方式
- 递归查询
- 迭代查询
递归查询:如果主机所询问的本地域名服务器不知道被查询的域名的IP地址,那么本地域名服务器就以DNS客户的身份,向其它根域名服务器继续发出查询请求报文(即替主机继续查询),而不是让主机自己进行下一步查询。
迭代查询: 如果主机所询问的本地域名服务器不知道被查询的域名的IP地址,他会告诉你另一个可能知道改域名的服务器的地址。
DNS缓存
为了提高效率,DNS服务器再接收到一个查询结果时会将其存储在本地并设置一个过期时间,期限内再次被询问这个domain时可以直接返回结果。
传输层
运输层主要是提供TCP和UDP两个协议,为应用层的应用和服务提供传输支撑。
TCP
- TCP 提供一种面向连接的、可靠的字节流服务
- 在一个 TCP 连接中,仅有两方进行彼此通信。广播和多播不能用于 TCP
- TCP 使用校验和,确认和重传机制来保证可靠传输
- TCP 给数据分节进行排序,并使用累积确认保证数据的顺序不变和非重复
- TCP 使用滑动窗口机制来实现流量控制,通过动态改变窗口的大小进行拥塞控制
TCP三次握手
- 客户端发送连接请求,SYN标志位设置为1,seq设置为一个随机(规避攻击)的client_isn
- 客户端请求到达服务器,服务器提取出seq,然后创建确认报文段并将SYN比特置为1,seq设置为随机的server_isn,ack设置为收到的client_isn+1
- 客户端收到确认报文段后,syn=0,ack=server_isn+1,seq=cilent_isn+1。此时可以携带应用层数据。
阶段 | syn | seq | ack | 应用层数据 |
---|---|---|---|---|
阶段一 | 1 | x | null | 不带数据 |
阶段一 | 1 | y | x+1 | 不带数据 |
阶段一 | 0 | x+1 | y+1 | 带数据 |
TCP四次挥手
- 客户端进程发出连接释放报文,并且停止发送数据。FIN设置为1,其序列号为seq=u。
- 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时客户端已不再发数据,但服务端仍可向客户端发数据。
客户端收到服务器的确认请求后,等待服务器发送连接释放报文,此时还将继续接收服务端传来的数据。
- 服务器数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1。
- 客户端收到服务器的连接释放报文后,发出确认,ACK=1,ack=w+1(w为服务器发送的最后一个数据的编号),而自己的序列号是seq=u+1。等待2*MSL(最长报文段寿命)的时间后客户端正式关闭连接(因为这个确认信号可能会丢失,所以等一等看看是不受丢失了)。
- 服务器只要收到了客户端发出的确认立即关闭,所以服务端比客户端先关闭连接。
流量控制和拥塞控制
参考:TCP流量控制、拥塞控制
区别:
流量控制:流量控制是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收,防止分组丢失的。
拥塞控制:拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况;
滑动窗口协议
如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,对发送方发送速率的控制,要让接收方来得及接收。
- 接收方收到数据包之后,可以在确定报文的同时告知自己的缓冲区空闲空间(接收窗口大小),发送方收到确认报文之后,会根据接收窗口的大小调整自己的发送窗口大小。
- 当接收窗口为0时,会停止发送数据,但是什么时候恢复呢? 解决方法是每隔一段时间就去发送一个测试报文,询问接收方的缓冲区是否空出来了。
拥塞控制算法
发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口,另外考虑到接受方的接收能力,发送窗口可能小于拥塞窗口。
还需要维持一个阈值ssthresh,用以选择不同的策略。
慢启动
cwnd < ssthresh时进行慢启动
- 初始状态时cwnd设置为1个MSS,然后每收到一个确认就增加一个MSS(1->2->4->8),呈指数速度增长。
- 如果出现一个超时事件,则将ssthresh设置为当前cwnd的一半,cwnd重新设置为1,重新开始慢启动。
- 但超过ssthresh时,再成倍数增加风险太大,停止慢启动。
拥塞避免
- 每次只增加一个MSS,即每个ACK增加MSS/N
- 出现超时,ssthresh设置为当前cwnd的一半,cwnd重新设置为1,重新开始慢启动。
快重传
- 快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。然后进入快恢复阶段。
快恢复
当发送方连续收到三个重复确认时,就把ssthresh减半(为了预防网络发生拥塞)。但是接下去并不执行慢开始算法(既然收到了三个重复的确认,那么可能情况还并不严重),所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh减半后的值,然后执行拥塞避免算法,使cwnd缓慢增大。
UDP
- UDP 是无连接的,即发送数据之前不需要建立连接(发送数据结束时也没有连接可释放),减少了开销和发送数据之前的时延
- UDP 使用尽最大努力交付,即不保证可靠交付,主机不需要维持复杂的连接状态表
- UDP 是面向报文的,发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界
- UDP 没有拥塞控制,网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的
- UDP 支持一对一、一对多、多对一和多对多的交互通信
- UDP 的首部开销小,只有8个字节,比 TCP 的20个字节的首部要短
使用UDP协议的应用有:域名系统(DNS)、简单网络管理协议(SNMP)、路由信息协议(RIP)等等。因为UDP不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以音频、视频和普通数据在传送时使用UDP比较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。比如我们聊天用到的QQ就是使用UDP协议。
对比
UDP | TCP | |
---|---|---|
有无连接 | 无连接 | 有连接 |
是否可靠 | 尽最大努力交付 | 可靠传输 |
传输方式 | 面向报文 | 面向字节流 |
端点 | 一对一、一对多 | 点对点 |
首部大小 | 首部小,仅8字节 | 首部开销大 |