知识梳理系列之四——网络协议TCP/IP、Http/Https
网络分层模型若干问题
本文是对基本知识的个人总结,旨在面试遇到时,能逻辑条理清晰。不是全面知识学习文本。
OSI七层模型和TCP/IP四层模型
-
OSI七层网络模型和TCP/IP四层模型图示
TCP/IP是一组协议族,包含很多协议,常见的比如UDP、HTTP、S-HTTP(HTTPS)、SSL/TLS、FTP、SMTP、POP3、DHCP、SOCKS等等,其中HTTP/FTP/SMTP/POP3/SOCKS等属于应用层协议。TCP/UDP协议是网络层协议、IP协议是传输层协议。
Socket网络套接字是一个使用TCP/IP的接口,方便访问和使用这些协议,本身不是协议。 -
其中HTTPS协议就是HTTP + SSL/TLS
SSL是Secure Sockets Layer的缩写,由Netscap发布,经IEEE标准化为TLS,目前主流的是TLS 1.1、TLS 1.2版本。 -
TCP与UDP的区别:
a. TCP保证数据在网络中的正确性、顺序性,而UDP不保证;
b. UDP由于不保证上述性质,省去了校验正确和顺序收发,在传输上更快速。
TCP/IP的握手与挥手
三次握手:
如下图所示:
说明:三次握手步骤:
- 客户端服务端分别打开传输控制块TCB,服务端进入LISTEN状态,客服端发起请求,并带数据SYN=1,seq=x(seq是一个序列数,序列数一般是发送数据的长度,握手时序列数都是+1不带其他数据),发送后客户端进入SYN_SEND状态;
- 服务端收到请求,并向客户端回复数据:ACK=1,SYN=1,ack=x+1,seq=y(表示收到了客户端的SYN=1,回复确认ACK=1,并且客户端的序列数+1,自己的数据序列数y),服务端进入SYN_RCVD状态;
- 客户端收到服务端的确认,并发送建立连接确认数据:ACK=1,ack=y+1,seq=x+1(表示客户端收到了服务端的确认,并回复服务器建立连接),客户端进入ESTABLISH,服务端收到客户端的确认数据后也进入ESTABLISH状态,此时连接建立。
为什么要三次握手?
可以看到完成第二次握手时,相当于服务端收到了客户端的请求,并且客户端也知晓的状态,为什么还需要进行第三次握手呢?
答案:主要是为了避免失效请求重复连接
一种常见场景:
一次客户端请求发出后,网络环境不畅,请求停留在网络中,客户端在长时间没有收到回复,尝试重新请求,此时网络畅通,并成功建立连接,完成数据交换并关闭连接,此时停留在网络中的上次请求又到达了服务器。
此时,如果只有两次握手将再次建立连接,这是不符合预期的!并且造成资源浪费。
那么是三次握手时,服务端收到失效的请求后,向客户端发送确认数据,但是客户端发现自己并没有请求,于是不做回复,此时,避免了失效请求导致重复连接!!
四次挥手
说明:四次挥手步骤:
- 客户端发起断开连接请求,FIN=1,seq=u,客户端进入FIN-WAIT-1状态;
- 服务端收到此请求后,回复客户端:ACK=1,ack=u+1,seq=v(此时没有回复FIN=1,因为服务端有可能有数据还没有发送完,只告知客户端我收到了你的FIN请求,我还有数据没发完),此时服务端进入CLOSE_WAIT状态,客户端进入FIN-WAIT-2状态;
- 直到服务端把最后的数据全部发送完成,服务端会再次向客户端发送:FIN=1,ACK=1,ack=u+1,seq=w(表示我最后的数据已经发完了),服务端进入LAST_ACK状态,等待客户端收到确认;
- 客户端收到后,发送ACK=1,ack=w+1,seq=u+1(告知服务端我收到了),并进入TIME_WAIT状态,服务端收到后就CLOSE了,客户端在TIME_WAIT超时后进入CLOSE。
为什么要四次挥手?
分解成两个问题:
- 为什么服务端回复客户端的FIN请求,有两次一次ACK,一次FIN/ACK?
因为服务端收到请求后,有可能还有客户端请求的数据没有发送完成,所以第一次ACK是告知客户端我收到你的FIN请求了,第二次FIN/ACK是告知客户端你要的数据我都发出去了。服务端等客户端确认知晓其已经发送完了数据,如果期间超时没有收到确认,服务端还会重发。 - 为什么客户端CLOSE之前有TIME_WAIT?
因为客户端在收到FIN/ACK后需要给服务端ACK,告知我收到了,如果客户端发完ACK,立即CLOSE,有可能服务端未收到ACK而关闭不了,TIME_WAIT保持客户端未关闭,是的服务端没有收到客户端的ACK时还可以再重发FIN/ACK;
另外一个作用是清除网络中的无效报文。
HTTP协议与HTTPS协议
HTTP是一种超文本传输协议,通常使用统一资源定位符URL来获取网络资源。
-
请求报文格式
请求头: 请求方法(如GET/POST) 资源路径或参数 HTTP协议版本
请求行: 就是Request对象里的一系列配置
比如:Host、User-Agent、Content-Type、Content-Length、Content-Encoding、
Content-Language、Accept-Type、Accept-Language、Connection(Keep-Alive)等等;
空行
请求体:(POST有/GET无)
-
响应报文格式
状态行: 协议版本 状态码 状态短语
响应头: Date 时间日期
charset 、Content-Type
Content-Length等等
空行
响应正文:比如 json 字符串等
状态码:状态码 含义 1xx 继续执行 2xx 成功 3xx 重定向 4xx 客户端错误 5xx 服务端问题 -
与Https的区别
区别在于在表示层使用了SSL/TLS,来进行身份校验(服务器CA证书),并使用密文传输请求数据。
http使用的是明文传输。
https会牺牲一部分速度,但总体影响不大;
常用的加密方式非对称加密、对称加密; -
附:有趣的加密原理(Diffie-Hellman算法)
非对称加密的离散对数方案:
已知公钥: 质 数 p 、 α 质数p、\alpha 质数p、α
ALICE要和BOB加密通信,不希望被EVE窃密;
希望有一种加密方式,用已知的加密算法,ALICE用私钥a加密数据Data发送给BOB,BOB接收到密文用自己的私钥b就能解密;EVE只能从网络中拿到两者加密后的数据,在一定时间内无法穷举出密码。
ALICE: 将计算: y = α a ( m o d p ) y = \alpha^a \ (mod \quad p) y=αa (modp) 将计算结果发送到网络中;BOB和EVE都可以收到
BOB:将计算: z = α b ( m o d p ) z = \alpha^b \ (mod \quad p) z=αb (modp) 将计算结果发送到网络中;ALICE和EVE都可以收到
ALICE:将收到的z 进行计算: p r e M a s t e r K e y = z a ( m o d p ) preMasterKey = z^a\ (mod \quad p) preMasterKey=za (modp)
BOB:将收到的y 进行计算: p r e M a s t e r K e y = y b ( m o d p ) preMasterKey = y^b\ (mod \quad p) preMasterKey=yb (modp)
此时发现ALICE和BOB算出了一致的结果preMasterKey ,这样就完成了加密通信的建立,确保两个身份合法的人连接到了一起,而EVE由于算不出一致的结果而无法窃密。
其中mod就是取余计算。
HTTP的Cache、Cookies、Session、Token等机制
-
由于HTTP是无状态协议,所以每次建立连接之间没有联系,如果遇到上一次的数据对下一个请求行为的结果有影响的情况,HTTP协议在协议层面是不好解决的,也不希望破坏无状态的特性。
于是就出现了Cookies、Session、Token等机制。 -
而Cache机制主要是为了降低服务器的负载,在一些场景下直接使用缓存而不是直接请求的方式节约资源、提高响应速度。
Cache
- 在响应报文的响应头中有一个参数:Cache-control: 字段。
这个字段就是设置缓存策略的。
常见的缓存策略有:
缓存策略名 | 含义或用途 |
---|---|
no-store | 不保存任何缓存,每次都重新请求服务器获取数据,相当于没有缓存。 |
no-cache | 保存缓存,但是每次都先请求服务器确认数据是否发生了变化。 1. 若数据未变化,服务器返回304,使用缓存数据; 2. 若数据变化,服务器返回新的数据供客户端使用,客户端更新缓存。 |
max-age | 将设置一个最大新鲜时间。若未超时,直接使用缓存;若超时,向服务器请求数据。 |
private | 默认的配置,只允许单个客户端缓存 |
public | 允许网络代理和客户端缓存 |
s-maxage | 表示public的缓存的最大新鲜时间 |
max-stale | 表示缓存过期后仍然可用的最大时间 |
min-fresh | 表示响应获取到后,缓存的最少新鲜时间,min-fresh不能大于max-age,否则失效导致min-fresh=max-age |
must-revalidate | 在使用缓存之前必须验证资源是否新鲜 |
一般,public和s-maxage组合使用;
no-cache的优先级更高,no-cache相当于max-age=0 + must-revalidate;
must-revalidate的优先级比max-age更高;
如果没有no-cache或must-revalidate才执行下面的步骤:
a. 缓存当前的时间age+min-fresh <= max-age 时,认为缓存新鲜可用;
b. age+min-fresh > max-age && age+min-fresh <= max-age + max-stale时,表示虽然缓存已经过期了,但是仍然可用,响应头会挂110 警告代码;
c. age+min-fresh > max-age + max-stale时,表示缓存过期不可用,必须重新请求拉取数据。
- 对比缓存相关属性
响应头除了会返回Cache-control字段还会有其他的,主要是:ETag、If-Modified、If-Modified-Since、If-None-Match;
缓存字段名 | 含义或用途 |
---|---|
ETag | 是服务器对某个请求的响应,当前的资源的一个特定标识 |
If-None-Match | 是客服端再次请求服务器时,请求的这个资源的标识 |
这两个是一对,都是资源标识,一个是第一次请求,服务端传给客户端的资源的代号;
一个是下次客户端再请求时,回传给服务端,要获取的资源的代号。
缓存字段名 | 含义或用途 |
---|---|
If-Modified | 是服务器响应的资源的时间标识,是截止到响应为止,资源最新被修改的时间 |
If-Modified-Since | 是客户端再次请求资源时,回传给服务器的客户端当前的资源时间标识。 1. 若服务器对应资源(相同ETag)的最新被修改时间变化了(If-Modified > If-Modified-Since),服务端将重新下发新的资源; 2. 若服务器对应资源最新被修改时间未变,说明资源未变,返回304直接用cache |
这两个也是一对,是一对各自持有的时间标识。用来判断资源是否修改。
总结:Cache-control 字段规定了是否缓存、缓存在哪、缓存超时多久(过期时间);ETag/If-Modified系列确定了资源有没有变化。
Cookies、Session、Token
Cookies、Session、Token都是为解决无状态问题出现的,各有差别。
Cookies在服务端的响应头中设置Set-cookies配置
Cookies是将状态数据保存在客户端,在每次请求都自动带上(对范围有要求,只能带上>=的),这种的缺点是每次访问相同的服务器页面就会带上,缺乏对用户身份的验证。
Session是服务端给客户端配一个唯一的session id来标记客户端,只有session id由客户端保存,其余数据都保存在服务端。服务端每次根据客户端请求时提交的session id在自己的散列表中查询,来确定客户端身份和数据。
session id的保存形式可以是客户端cookies保存或者请求时作为参数的形式(不完全依靠cookies);
这种方式当遇到分布式服务,需要给各个主机拷贝session散列表,或者提供一台专门创建、保存、查询、删除session id的服务器管理。
缺点就是:拷贝过程繁琐,或者一旦专门服务挂了,整个系统就宕机了。
Token就是专门针对Session的缺点提供的一种方案,由服务端密钥和加密算法生成字符串并签名后,授权给客户端,客户端只需要保存这个字符串,每次请求时上传,由服务端解密、校验签名即可获得用户身份和状态。