基于TCP/IP四层模型浅析计算机网络基本知识(自上向下)

706 阅读16分钟

模型

img

应用层、表示层、会话层

HTTP协议

HTTP请求报文和响应报文

请求报文

方法(METHOD)
方法用途
GET向服务器发送某个资源,通过query拼在请求地址后,受url长度限制(比如IE8对url长度限制是2048个字符),传送的数据量较小。
POST通常支持表单数据(formData),传输内容在body中,传输的内容没有限制,header是multipart/form-data格式,更高效的传输二进制数据
HEAD不获取资源的情况下,对资源首部的检察
PUT向服务器写入文档,允许用户创建WEB页面
DELETE请求服务器删除URL中指定的资源
通用首部字段
字段名说明
Connection指定连接方式,默认为keep-alive长连接
Date报文创建时间
Cache-Control控制缓存行为
请求首部字段
字段名说明
Host接受请求的主机名和端口号
Range如果服务器支持范围请求,就请求资源的指定范围
Cookie客户端用他向服务器传送数据
Accept用户代理可处理的媒体类型
响应报文

状态码
状态码对应内容
1xx请求已接受,需要继续处理
2xx成功,请求已经被服务器接收
3xx重定向,重定向目的地址在本次响应的Location域中指明
4xx请求错误
5xx服务器无法响应
响应报文首部字段(常用)
字段名描述
Age资源创建经过实践
ETag资源匹配信息
Location(当重定向时)高质客户端实体实际位于何处
ServerHTTP服务器安装信息
Last-Modified实体最后一次被修改的日期和时间

缓存机制

在客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有请求资源的副本,就可以直接获取。

常见的http缓存只能缓存get请求的数据。

强缓存

HTTP状态码:200

直接从浏览器的缓存数据库获得数据

协商缓存

HTTP状态码:304

请求头:ETag,Last-Modified

首部字段作用
eTag在请求的响应报文中返回的一串内容W/"a-QFZ79AprHeNlMfPMKXyEUV+lyOg"
if-none-match第二次请求,请求头中带有该字段,值和eTag值相同W/"a-QFZ79AprHeNlMfPMKXyEUV+lyOg"
last-modified第一次请求一个地址,响应报文标记文件在服务端最后一次被修改的时间Fri , 12 May 2006 18:53:33 GMT
if-Modified-Since第二次请求一个地址,浏览器向服务器发送请求报文,值是第一次请求的last-Modified的时间,询问在这个时间后,资源是否修改过。Fri , 12 May 2006 18:53:33 GMT
缓存过程

img

  1. 检查cache-control
cache-control属性名解释
max-age响应返回后一定时间内,可以使用缓存
private只有浏览器能缓存,中间代理服务器不能缓存
no-cache跳过强缓存,发哦是那个HTTP请求,进入协商缓存
no-store不进行缓存
s-maxage代理服务器的缓存时间

如果再缓存时间内,直接返回缓存,没有发起http请求。

  1. 如果不在缓存时间内, 进入协商缓存,发起HTTP请求
    • 如果使用Last-Modified,即第一次请求地址的时候,响应返回资源上一次修改时间,第二次请求该资源,将这个时间作为Last-Modified的值传入,服务器将比对在这个时间之后是否有更新,并把这个值作为响应报文的if-Modified-Since返回
    • 如果使用ETag,即第一次请求的时候,响应报文返回ETag,第二次请求该资源,将这个值作为If-None-Match的值发送,服务器将会把这个值和服务器上的ETag比对,如果一致,返回304,如果不一致,返回新的资源,状态码200

同源策略

即:协议+域名+端口号都相同,例如:

地址一、www.domain.com

地址二、www.domain.com

地址三、child.domain.com

地址四、www.domain.com:8081

以上这些都不属于相同的地址

地址五、www.domain.com?username=name

和地址一属于相同地址

CORS

​ IE10以上支持CORS。

  • 简单请求:

    • 请求方法为GET,POST,HEAD
    • 请求头取值范围
      • ACCEPT
      • ACCEPT-LANGUAGE
      • CONTENT-LANGUAGE
      • CONTENT-TYPE
    • 对于简单请求,浏览器在发送请求之前,自动添加origin字段,说明请求来自哪个源,响应报文添加Access-Control-Allow-Origin字段,返回这个源,如果浏览器发现这个origin不在这个字段内,浏览器会拦截这个响应。
    • Access-Xontrol-Allow-Credentails是bool值,是否允许Cookie,默认false
    • Access-Control-Expose-Headers能拿到这个字段声明的响应头字段。
  • 非简单请求

    • 会先进性预检,将请求头用OPTIONS方法发送
    OPTIONS /HTTP/1.1
    Origin:当前IP
    Host:xxx.com
    Access-Control-Request-Method:PUT // cors请求要用的类型
    Access-Control-Request-Header:X-Custom-Header // cors请求要加什么请求头
    
    • 预检的响应字段
    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: * //允许请求的的源
    Access-Control-Allow-Methods: GET, POST, PUT // 允许的方法
    Access-Control-Allow-Headers: X-Custom-Header
    Access-Control-Allow-Credentials: true // 是否允许cookie
    

keep-alive和多路复用

keep-alive

建立一次长连接,多次请求都复用该连接。

keep-alive有一个 timout时间设置参数,如果在这个等待时间里没有受到浏览器发来的请求,就关闭长连接。

同时可以根据Content-Length字段来判断数据是否已经全部接受。

但是在并行的情况下,并发的请求在连接上的响应是顺序的,这样才不会乱套

  1. 请求资源A
  2. 相应资源A
  3. 请求资源B
  4. 相应资源B

如果只能知道每个response对应的request,并发的请求可以只需要在一次TCP连接里了,这就是HTTP2.0的多路复用。

多路复用

每个request都有单独的id,用id去区分请求,因此请求不需要等前一个获得响应之后再发送。

  1. 请求资源A,id:1
  2. 请求资源B,id:2
  3. 返回id:1的响应,对应获得资源A的响应
  4. 返回id:2的响应,对应获得资源B的响应

1.0/1.1/2.0

1.01.1
只支持GET POST HEAD支持包括PUT、DELETE等其他方法
无状态,无连接增加了缓存机制
不支持断点续传增加Range请求头,支持断点续传
1.12.0
keep-alive多路复用,允许出现两个并行的响应
重复发送头部头部压缩,建立head-cache,无需重复发送头部数据
字节流基于二进制分帧,更稳健

使用XMLHTTPRequest封装基础的ajax请求

const $ajax = (options)=>{
	options = Object.asign({
        url:'http://localhost:3000',
        method:"GET",
    },options)
    
    return new Promise((resolve,reject)=>{
		let xhr = new XMLHTTPRequest();
        xhr.open(options.method,options.url);
        
        xhr.onreadystatechange = ()=>{
            // readyState: 0->请求未初始化 1->连接已建立 2->请求已接受 3->请求处理中 4->请求已完成
            if(xhr.readyState===4){
                // 状态码是3或者4开头都认定是成功的
                if(/^(3|4)[0-9]{2}/.test(xhr.status)){
                    resolve(JSON.parseInt(xhr.responseText))
				}else{
                    reject(xhr)
                }
            }
        }
        
        xhr.send();
    })
}

HTTPS协议

加密

在HTTP协议总,数据是以明文传输的,因此有一定的安全风险,HTTPS协议在发送请求之前先建立SSL连接,用于数据加密和身份验证。

对称加密

加密和解密用的是同一个密钥,没有非对称加密安全,但是效率高。例如DES,AES。

非对称加密

加密和解密用的不是同一个密钥,有一对公钥和私钥,一般用公钥加密,用私钥解密,安全性高,但是效率低。

例如RSA。

了解了对称加密和非对称加密的特点,我们就不难理解HTTP加密的机制,先生成对称加密密钥用于加密通讯,提升传输效率,再用非对称加密保证对称加密密钥在传输时的安全,可能有点绕,我们一步一步看。

  1. 浏览器和服务器建立SSL连接
  2. 服务器接受SSL连接,发送公钥A给浏览器
  3. 浏览器接收公钥A,并生成生成用于通讯的对称加密密钥B
  4. 浏览器用公钥A密钥B进行加密,生成密钥C,发送给服务器
  5. 服务器接受到密钥C,用私钥A解密获得密钥B
  6. 双方用密钥B进行通信

但是这个时候又有一个问题,浏览器不知道,接受到的公钥是不是正确的服务器发来的,因此需要数字签名进行身份验证。

  1. 服务器将个人信息(认证主体信息)通过摘要算法生成摘要A,再通过CA(数字证书颁发机构)申请的私钥A生成数字签名
  2. 服务器将个人信息数字签名一起发送给浏览器
  3. 浏览器用CA拿到的公钥A解密数字签名获得摘要A,然后将服务器发送的个人信息生成摘要B,如果身份正确,两个摘要的内容应该是一样的。

DNS寻址

DNS协议通过域名解析服务ip地址,以下讨论非CDN资源寻址过程

  1. 客户端发起查询请求,在本地缓存中查找,如果找到,返回ip地址
  2. 向根域名服务器发送请求,返回包含下一级dns服务器的地址返回到客户机的dns服务器地址
  3. 客户机dns服务器分局返回的信息继续向下查找,直达获得ip地址
  4. 本地dns服务器将结果返回客户机,同时建立本地映射

CDN

  1. 当域名解析系统遇到CDN子域名,将域名解析权发给CNAME指向的CDN专用DNS服务器

  2. CDN专用DNS服务器将全局负载均衡设备IP返回给用户,浏览器向负载均衡设备发起请求

  3. 全局负载均衡设备通过IP地址和URL,返回一个局部负载均衡设备,浏览器向局部负载均衡设备发起请求

  4. 局部负载均衡设备根据:

    • IP地址:寻找最近的节点
    • url:寻找含有目标资源的节点
    • 服务器负载:寻找还有能力的服务器

    返回一个ip地址,让浏览器发起请求

  5. 缓存服务器响应请求,如果缓存服务器上没有内容,则向上一级缓存服务器请求,直到原网站把资源拉到本地

传输层(端对端)

TCP协议

报文格式(首部20字节)

img

累积确认机制

当报文分段,数据序号(seq)表示当前包的序号,确认序号(ack)表示下一个需要的包的序号。

  1. 服务器发送第一个包,seq=1
  2. 服务器发送第二个包,seq=1000
  3. 服务器发送第三个包,seq=2000,这个包因为某种原因丢失了
  4. 浏览器收到前两个包,返回ACK=2000
  5. 服务器收到前两个包已经收到了,把这两个包移除重传队列
  6. 服务器发送第四个包,seq=3000
  7. 浏览器收到第四个包,把它放入缓存,不返回ACK,等待第三个包
  8. 服务器没有收到第三个包的ACK,因此重传报文三
  9. 浏览器成功接收第三个包,现在包一二三四都到达浏览器,返回ACK
  10. 服务器把报文三、四移出重传队列,此时队列为空,结束发送。

三次握手

  1. 客户端 -> 服务器: SYN, seq=x

    客户端发送后状态:SYN-SENT 此时服务器状态LISTEN

  2. 服务器 -> 客户端:SYN,ACK,seq=y,ack = x+1

    服务器接收到SYN后状态:SYN-RCVD 客户端收到ACK之后状态变为:ESTABLISHED

  3. 客户端 -> 服务器:ACK, seq = x +1, ack = y+1

    服务器收到ACK之后状态变为:ESTABLISHED

为什么是三次握手?两次不可以吗?四次不可以吗

三次握手是为了确认客户端和服务端都有发送和接收消息的能力,因此:

​ 第一次握手:检验客户端发送消息的能力

​ 第二次握手:检验服务器发送消息和接收消息的能力

到这里为止,我们还不知道客户机是否有能力接受消息。

如果碰到消息发送超时,重新发送请求的状况,对于前一个请求客户机是不会再产生响应的,这样通道一直打开,服务器一直等待浏览器响应,非常耗费性能。

因此我们需要第三次握手,检验客户端是否可以接收消息。

至于为什么不要第四次握手,因为三次已经足够了,再多的握手只能延长连接建立的时间。

快速建立TCP连接TFP

第一轮三次握手
  1. 客户端发送SYN
  2. 服务器端接收SYN,计算SYN Cookie,放到Fast Open选项中,然后返回SYN和ACK
  3. 客户端收到,发送ACK,缓存SYN Cookie
第二轮三次握手
  1. 客户端发送,SYN,SYN Cookie和HTTP请求。
  2. 服务器返回ACK,SYN
  3. 服务器验证cookie合法性,如果合法,发送HTTP响应
  4. 客户端发送ACK

这样的好处是节省了一个RTT,可以提前获得响应。

四次挥手

挥手可以由任意一方开始,以下例子以客户端先发起挥手请求为例:

  1. 客户端 -> 服务器: FIN,seq=p

    客户端状态:ESTABLISHED->FIN-WAIT-1

  2. 服务器 -> 客户端:ACK,ack=p+1

    服务器状态:ESTABLISHED-> CLOSED-WAIT 客户端状态: CLOSED-WAIT-1 -> CLOSED-WAIT-2

  3. 服务器 -> 客户端:FIN,ACK,seq=q,ack=p+1

    服务器状态:CLOSED-WAIT -> LAST-ACK

  4. 客户端 -> 服务器:ACK,ack=q+1

    客户端状态: CLOSED-WAIT-2 ->TIME-WAIT

为什么两次FIN要分开发送

发送FIN是表示某一方的数据已经发送完了,如果服务器接收到FIN立即也发送FIN,这样就会导致服务器数据没发送完,连接就关闭了。

拥塞机制

就像泳池希望出水速度和入水速度相同,这样水池的水量会保持不变。

网络中也希望输入负载和网络吞吐量达到平衡,避免负载过多导致的丢包和负载过小导致的浪费

TCP有四种拥塞控制的算法:

  1. 慢启动

    发送方初始拥塞窗口cwnd为1,当发送方接收到响应,此时cwnd+1,这样一开始向网络注入的报文段少,每经过一个RTT,cwnd翻倍,直到到达阈值

  2. 拥塞避免

    到达阈值之后,每一个RTT,cwnd只增加1,从慢启动的指数增加变成了线性增加

  3. 快重传

    如果再传输过程中,碰到丢包的情况,像之前提到的,收到了1,2,4,但是没有收到3,这时返回的一律是ACK=3,当服务器收到三个相同的ACK时,就意识到丢包了,将立即重传

  4. 快恢复

    当服务器发现丢包了,将意识到现在的网络已经有点拥塞了,此时:

    • 拥塞阈值 = cwnd/2
    • cwnd = 拥塞阈值
    • cwnd 线性增长(拥塞避免)

TCP和UDP的比较

TCPUDP
面向连接的(需要三次握手建立连接)无连接的
可靠的(有超时重传、拥塞机制,如果网络不佳TCP会自己调整wcnd)不可靠
字节流的(将IP包变成字节流)基于数据报的

网络层(IP,点到点)

IP

报文格式(首部20字节)

img

标志位(三位)

MF = 1:表示后面还有分片

DF = 0:表示不允许分片

子网划分

internet组织机构定义了五种IP地址。全1是广播地址,全0表示主机地址

类别范围掩码
A类1.0.0.1-126.255.255.254255.0.0.0(8位网络号,后24位主机号)
B类128.1.0.1-191.255.255.254255.255.0.0
C类192.0.1.1-223.255.255.254255.255.255.0
D类224.0.0.1-239.255.255.254网络号224-239,用于多路广播
E类1111开头,网络号240-255

私有IP地址

​ 私有IP是本地局域网上的IP地址,保留下来用于企业内部网络分配所使用的地址:

类别范围
A10.0.0.0-10.255.255.255
B172.16.0.0-172.168.255.255
C192.168.0.0-192.168.255.255

NAT协议

私有地址->全局地址的映射。

  1. 私有地址为10.1.0.10的主机想要访问web服务器162.105.129.12
  2. 消息发送给NAT路由器
  3. 路由器记录他的私有地址和端口号,分配他一个全局地址125.1.2.3,把请求发送出去
  4. web服务器响应请求,通过125.1.2.3,找到私有地址10.1.0.10返回给他应答。

img

DHCP协议

动态主机配置协议。

  1. 保证同一IP地址同一时刻只被一台主机使用
  2. 自动分配:可以给用户分配永久固定的IP地址
  3. 动态分配:DHCP服务器给主机指定一个具有时限的IP地址,时间到期或者主机放弃地址之后,改地址可以给其他主机使用(只有动态分配可以使用主机废弃的IP地址)
  4. 手工分配:DHCP只是返回分配结果

ARP协议

IP地址->MAC地址的映射,因为MAC地址工作在数据链路层,IP地址工作在网络层因此不能直接打交道,当以太网发送IP数据包的时候,需要先封装MAC地址包头,再向上封装IP地址。

同时RARP协议用于MAC地址->IP地址的映射。

数据链路层(帧)、物理层(比特流)

以太网的帧格式(14字节)

以太帧结构(格式)

  • 前同步码:8字节,固定的,为了使接收端适配器接受MAC帧时快速调整时钟频率

  • 定界符:(六位)表示后面时以太网MAC帧

  • 目的地址:目的MAC地址,6位,网卡接收一个帧的时候会检查目的地址和适配器物理地址是否相同,如果不同,直接丢弃

  • 类型:上层协议

  • 数据:IP数据包,最大传输单元(MTU)时1500字节,最小时46字节,如果没有到46字节将自动填充