深入理解计算机网络(1)

190 阅读13分钟

七层网络模型

  • 应用层:为应用程序提供交互服务,主要有DNS,Http,FTP协议
  • 表示层:实现数据格式转换,加密解密功能
  • 会话层:为网络中的两个节点建立会话连接
  • 传输层:提供通用的传输协议,负责实现端到端的通信,主要是TCP和UDP协议
  • 网络层:负责实现点对点的通信,主要是IP协议
  • 数据链路层:把网络层传下来的IP数据包封装成帧并在链路上传送
  • 物理层:负责两个物理节点之间的比特流透明传输

前三层工作在操作系统的用户态,后四层工作在操作系统的内核态。

从键入网址到网页显示的过程

  1. 从源主机出发

    • 浏览器解析URL,生成http请求,使用DNS将域名转化为IP地址
      • 操作系统先查看hosts文件是否有静态映射,然后浏览器查看自身缓存,操作系统查看自身缓存,最后检查本地DNS服务器缓存。
      • 若以上都没有,本地DNS服务器再去询问根域名服务器,根服务器返回顶级服务器地址,本地服务器再去找顶级服务器,顶级服务器返回权威服务器地址,本地服务器再去找权威服务器查询到IP地址
    • Http包加上TCP头部组成TCP包,实现端到端的可靠传输
    • TCP包加上IP头部组成IP包,实现点到点的传输
    • IP包加上MAC头部组成MAC包,实现链路中两节点传输
    • 网卡驱动程序获取数据包后,将其DMA到网卡可访问的内存区域。在开头加上报头和起始帧分界符,在末尾加上帧校验序列FCS,最后将包通过网线发送。
  2. 数据包到达交换机,被转发给路由器,准备离开当前子网

    • 交换机(工作在MAC层/数据链路层)用于局域网内部的数据通信
    • 交换机没有IP地址,故接收到的所有包都保留。它会对包做FCS校验,在自己的MAC地址表中看是否能找到目标MAC地址,若找到则将包从对应端口发出,若未找到则把包转发到所有端口。
  3. 数据包到达路由器,被转发给下一个路由器或目标设备

    • 路由器(工作在网络层)用于不同网络间通信,各个端口都有MAC地址和IP地址。
    • 路由器只接收转发给自己的包,根据IP头部中的目标IP地址查询路由表(与表中目标IP地址做匹配),若找到则从对应接口转发到下一跳路由,若找不到转发到默认路由,所以在传输过程中源IP和目标IP始终不变,变化的是MAC地址。
  4. 数据包到达目标主机

    • 数据包抵达服务器,服务器开始拆包,依次检查并拆除MAC,IP,TCP头部。
    • 如果还未建立TCP连接就三次握手建立连接,如果TCP序列号是自己想要的就放入缓存并返回ACK,否则丢弃。
    • 服务器再通过TCP头部中的端口号把包发给Http进程,HTTP进程解析请求并返回对应HTTP响应报文

Http协议

HTTP协议即超文本传输协议,是一种用于分布式、协作式和超媒体信息系统的应用层协议。它是Web的基础,主要用于从网络传输超文本到本地浏览器的传输协议。Http的优点是简单,灵活,易扩展,跨平台,但是也有无状态,明文传输,不安全等缺点。

Http报文

请求报文

  • 请求行:请求方法+URL+协议版本
  • 消息头:各种首部字段
    • Host:服务器域名和端口号
    • Authorization:客户端的认证信息
    • Cookie:用户会话信息
    • Connection:Keep-Alive(长连接)
    • Content-Type:请求体的内容类型
    • Content-Length:请求体的长度
    • Accept:接受数据类型
    • Accept-Encoding:接受的压缩方式
  • 消息体:表单数据(kv方式编码),JSON数据,文件二进制数据

响应报文

  • 状态行:状态码+状态短语+协议版本
  • 消息头:各种首部字段
    • Content-Length:响应内容长度(解决消息体粘包问题)
    • Content-Type:响应数据类型
    • Content-Encoding:数据压缩格式
    • Etag:资源版本标识符,用于缓存验证
    • Redirection:重定向地址
    • set-Cookie:设置客户端的Cookie
  • 消息体:纯文本,HTML数据,JSON数据,文件二进制数据
Http状态码
  • 101:通过Upgrade头字段进行协议切换
  • 200:服务器已成功处理请求。
  • 301:永久重定向,请求资源已不存在,用新的URL再次访问。
  • 302:临时重定向,请求资源还在,但是暂时用新的URL访问。
  • 304:资源未修改,可使用当前缓存
  • 400:请求格式错误。
  • 403:服务器拒绝执行请求。
  • 404:服务器找不到请求的资源。
  • 500:服务器内部错误。
  • 503:服务器忙,暂时无法响应
请求方式
  • Get:从服务器获取指定资源
    • 参数写在URL中,URL仅支持ASCII,且浏览器对URL长度有限制
    • Get方法是安全的,因为它用来读,不改变服务器上的数据
    • Get方法是幂等的,多次读操作结果相同,所以可以为Get请求做缓存
  • Post:根据请求体对指定资源做出处理
    • 参数写在请求体中,格式任意,浏览器不对请求体大小做限制
    • Post方法是不安全的,会修改服务器上的资源
    • Post方法是不幂等的,多次提交数据会创建多个资源,所以不能为Post请求做缓存
  • Put:对应修改数据
  • Delete:对应删除数据
Http缓存技术
  • 强制缓存:只要浏览器判断缓存资源没过期,就直接使用浏览器的本地缓存。
  • 协商缓存:本地资源过期(未命中强制缓存),浏览器询问服务器是否可以继续使用本地缓存(通过响应头中的Etag字段实现,若资源没变化返回304,有变化返回200)
Http发展历史

Http1.1

  • 使用了长连接:避免发一个请求就要建立一个TCP连接,只有一方提出断开连接才断开(有时间限制)
  • 管道传输:发送方不用等接收方响应就能发下一个请求,但是服务器还是必须按照接收请求的顺序发送响应。(基本不使用)

Http2

  • 头部压缩:客户端和服务端都维护一张头信息表,所有字段都存入这个表,生成索引号,后续只发索引号,不发送具体字段
  • 二进制格式:不再使用纯文本形式的报文,而是使用二进制格式,提高传输效率
  • 并发传输:Http1.1存在队头阻塞问题,Http2引入Stream概念。 一条TCP连接中包含多个Stream,每个Stream有唯一id。不同Stream可以并行发送数据,不需要有序,但每个Stream中的数据有序。
    • TCP是字节流协议,必须保证收到的字节数据是完整且连续的。当序列号较低的TCP包丢失了,序列号较高的TCP包收到后只能放在内核缓冲区中,应用层无法读取
    • Stream没有解决TCP队头阻塞问题,如果某个Stream的数据包丢失导致TCP层面的数据不连续(TCP丢包),那么服务器也无法接收后续TCP包,则所有Stream流都会卡住,等待丢了的TCP包重传回来
  • 服务器主动推送资源:服务器和客户端双方都可以建立Stream发送消息。

Http3

  • Http2队头阻塞的原因是TCP,所以Http3把TCP改为UDP(使用QUIC协议)并在一定程度上实现了可靠传输
  • QUIC协议
    • 无队头阻塞:也使用类似Stream的概念,同一个连接并发传输多个Stream,当某个Stream丢包只会阻塞自己不会阻塞其他流(因为UDP可以不按顺序接收)
    • 更快建立连接:Http2的TCP和TLS需要分别握手,而QUIC包含了TLS,只需要1个RTT(只执行了TCP的前两次握手)就可以完成握手,确认对方的连接ID
    • 连接迁移:TCP基于四元组确定TCP连接,IP地址变化就要重新连接。而QUIC使用连接ID标记两个通信端,即使网络变化后IP地址变化了,只要仍然保有上下文信息就可以直接复用原连接
Https

Https解决了Http的窃听风险,篡改风险,冒充风险。分别使用加密算法,信息摘要算法,CA证书实现。

防止窃听:TSL协议加密

Https在TCP层和Http层之间加了TLS安全协议,在TCP三次握手后还需要TLS四次握手才可进行加密传输。TLS四次握手流程如下(基于RSA算法):

  • 客户端向服务器发起加密通信请求,即ClientHello请求,包括客户端产生的随机数(Client Random)
  • 服务器收到请求后回复响应,即SeverHello,包括服务器产生的随机数(Server Random)和数字证书
  • 客户端收到响应后通过浏览器中的CA公钥,确认服务器数字证书真实性,随后从数字证书中取出服务器公钥,用它加密报文,向服务器发送第三个随机数(pre-master key)(此时客户端可用三个随机数计算出会话密钥) 客户端握手结束,把之前发的内容做个摘要,供服务器校验。
  • 服务器收到第三个随机数后也可以计算出会话密钥,服务端握手结束,将之前内容做摘要供客户端校验。
  • 后续服务器和客户端使用计算出来的会话密钥加密内容,通过Http协议传输

防止冒充:CA证书身份认证

  1. 服务器把自己的公钥注册到CA机构
  2. CA机构用自己的私钥为服务器的公钥签名并颁发数字证书
  3. 客户端拿到服务器的CA证书后使用浏览器内置的CA公钥确认证书真实性
  4. 客户端从证书获取到服务器公钥并用其加密报文
  5. 服务端用私钥解密报文

防止篡改:信息摘要算法

  • MD5:hash函数,最常用,但安全性差
  • SHA-1,SHA-256,SHA-3:hash函数,较常用,安全性高

Https一定安全可靠吗

  • 若是有中间人服务器,分别与客户端和服务器进行通信,且用户信任了此中间人服务器(或直接在客户端伪造CA证书),那么传输数据可被窃听。
  • 但这不是Https本身的问题,实际上很多抓包工具能看到Https协议的传输数据正是利用了这一点,抓包工具会在客户端导入抓包工具生成的证书,浏览器会信任这个证书。
  • 如何避免被中间人抓取数据:使用Https双向认证,一般Https是单向认证即客户端验证服务端身份,但是服务端不验证客户端身份,如果使用双向认证,一旦服务端验证到客户端不可信就会中止通信。
Http与RPC
  • RPC与Http都是基于TCP的应用层协议,只不过它们定义了不同的消息格式且用于不同的场景。
  • Http是超文本传输协议,用于客户端和服务器之间通信。RPC是远程过程调用,是一种调用方式,用于各个微服务之间通信,实际上RPC协议也可以基于Http或UDP。常用的协议如gRPC
  • Http VS RPC
    • 服务发现:得到目标服务器的IP地址和端口。Http通过DNS服务器去解析IP地址,RPC通过专门的中间服务去保存服务名和IP地址,如Etcd。
    • 底层连接:都使用长连接,但RPC还使用了连接池来复用连接,实际上Http也可以建连接池
    • 传输内容: Http中消息头和消息体主要是字符串(Http1.1),并使用JSON序列化结构体数据。RPC使用Protobuf序列化(性能更好),且RPC不需要考虑各种浏览器行为
  • gRPC协议
    • 基于Http2,支持双向通信,头部压缩,Stream机制,二进制格式,性能较高。
WebSocket

WebSocket也是基于TCP的协议,用于服务器主动给客户端发送资源。服务端主动推送资源的方案包括:

  • 使用Http定时轮询:客户端定时去询问服务端,服务端有数据就发送给客户端。这种方案需要发送很多Http请求,且请求频率会影响用户体验。
  • 使用Http长轮询:Http请求发出后会给服务器留一定的时间做响应,例如3s,超过时间没响应即为超时;如果将超时时间设置的很大,例如30s,那么30s内服务端有数据了就可以返回给客户端。这在扫码登录这样只需要服务端发送一次回应的场景中很实用。
  • 使用WebSocket协议:WebSocket适用于服务端需要与客户端频繁交互的场景。
  • 使用SSE协议:SSE基于Http,只允许服务端向客户端发送数据,比起WebSocket,SSE更加轻量级,实现更加简单,通信开销更小。适用于服务端单向推送数据给客户端的场景。

WebSocket连接过程

  • TCP三次握手建立连接后,使用Http协议进行一次通信。若是普通Http请求则继续,若浏览器想升级协议建立WebSocket连接,就会将请求的Connection字段设置为Upgrade。
  • 然后服务器回应101状态码,就会走WebSocket握手流程,后续使用WebSocket格式的数据进行通信。
  • WebSocket的数据格式也是消息头+消息体,消息头中包含消息体长度,以此解决粘包问题。
Http的Cookie与Session
  • cookie和session都是用于解决Http协议无状态的问题。
    • Cookie是服务器发送给用户并保存到用户浏览器的数据,会在浏览器的下一次访问中被带上发送到服务器,可用于会话状态管理。
    • Session是存储在服务器的数据,保存服务器与客户端一次会话的信息,会话关闭时session失效。
  • 用户第一次请求服务器时,服务器根据用户信息生成一个session,请求返回时将session的唯一标识sessionId返回给浏览器,浏览器收到后将其存入cookie中,同时记录此sessionId属于哪个域名。
  • 用户第二次访问服务器时,如果存在cookie信息将其发送给服务器,服务器从cookie中获取sessionId,根据sessionId查到对应session信息,没找到说明用户未登录或登录失效,找到证明用户已登录。