图解网络-总结
五类问题:
- HTTP 基本概念
- Get 与 Post
- HTTP 特性
- HTTPS 与 HTTP
- HTTP/1.1、HTTP/2、HTTP/3 演变
HTTP
HTTP 基本概念
基本概念
首先先回顾一下网络的五层协议:物理层(光纤)、数据链路层(以太网、ppp不太熟)、网络层(IP,实现主机与主机之前的通信,也叫点对点通信)、传输层(tcp)、应用层(http)
参考:
http是超文本传输协议,可以这样理解:http是一个用在计算机世界里的协议,它使用计算机能够理解的语言确定了一种计算机世界中两点之前传输文字图片音频视频等等超文本数据的规范,以及相关的各种控制和错误处理方式(行为约定和规范)。
状态码
我经常用到的是100(跨域情况下post请求会先发一个options侦测一下是否可以进行跨域),200(成功),204(成功了但是没数据返回),206(断点续传,没用过),304(使用本地的缓存资源),403(没有权限),404, 500(服务器端错误),502(Bad Gateway)
常见字段
- host
- Content-Length
- Connection:常见值keep alive,用与请求复用
- Content-Type: json、html、form
- Content-Encoding: 数据压缩的办法,常见gzip
Get 与 Post
区别
- get用于读的请求,post用于修改数据的请求,这里引申出俩概念:安全和幂等,安全是不破坏服务器上的资源,幂等是多次执行相同的操作,结果都是相同的
- get能被缓存,post不能被缓存
- get发送一个tcp包,post发两个tcp包(https://www.zhihu.com/question/28586791)
HTTP 特性
优缺点
http1.1的优点:
这个之前不清楚
- 简单
- 灵活和易于扩展
- 应用广泛和跨平台
http1.1的缺点:
- 无状态
cookie、jwt - 明文传输
- 上面两个导致了不安全: 窃听、篡改、冒充
HTTPS 与 HTTP
区别
- http + 在tcp和http之间增加ssl/tls安全协议,使报文能够加密传输
- https在tcp三次握手后,还需要进行安全协议的握手过程
- http 80, https 443
- https协议需要想CA(证书权威及后申请数字证书),来保证服务器的身份是可信的
解决了http的不安全
- 信息加密:交互信息无法被窃取
- 校验机制:无法篡改,篡改了就不能正常显示
- 身份证书:可以证明网站的真实性
如何解决的
- 混合加密的方式实现信息的机密性,解决了窃听的风险
- 摘要算法的方式来实现完整性,它能够为数据生成独一无二的指纹,指纹用于校验数据的完整性,解决了篡改的风险
- 将服务器公钥放入到数字证书中,解决了冒充的风险
混合加密:在通信建立前,采用非对称加密的方式交换会话密钥,后续拿着会话密钥进行对称加密的交换数据
摘要算法(https://www.cnblogs.com/shichangming/p/10906040.html)用来实现完整性能够为数据生成独一无二的指纹,用于校验数据的完整性,解决了篡改问题
SSL/TLS协议
基本流程
- client向服务器索要并验证服务器的公钥
- 双方协商生产会话密钥
- 双方采用会话密钥进行加密通信
前两步是建立过程,也就是握手阶段,涉及到四次通信;前三次的通信会各自生成一个随机数,client 随机数 + server 随机数 + premaster(公钥加密的随机数) 算出会话密钥
配图原图看不清楚
HTTP/1.1、HTTP/2、HTTP/3 演变
http 1.1
http1.1提升的性能:
- 为了提升1.0中每个请求都会新建一个TCP连接,引入长连接,还记得上面的keep-alive吗
- 采用长连接,使管道传输成为可能。第一个请求发出去,不必等它回来,可以继续发第二个请求出去,减少整体相应时间。但还是要保持顺序
仍然存在的性能瓶颈:
- 头部没有压缩就发送,header信息越多,延迟越大
- 发送冗长的首部。每次互相发送相同的首部造成浪费
- 服务器是按照请求顺序响应的,如果服务器响应慢,会招致客户端请求不到数据,也就是队头阻塞
- 没有请求优先级控制
- 请求只能从客户端开发,服务器只能被动响应
http 2
http 2的优化:
- 头部压缩:HPACK算法:客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就发索引号
- 帧:数据是二进制格式
- 一个请求/回应的所有数据包成为数据流:不按照顺序、可指定优先级,客户端发出的编号是奇数,服务端发的是偶数
- 多路复用:一个连接中并发多个请求,不用按照顺序一一对应
- server push
总之,尽管到了http2,丢包仍是命门。多个http请求复用tcp连接,下层的tcp协议是不知道有多少http请求的。一旦发生丢包,就会出发tcp的重传机制,这样在一个tcp连接中的所有http请求都必须等待这个丢了的包重传回来。总而言之,这是基于tcp传输的问题。
http 3
直接将http的下层协议改为基于UDP的QUIC协议实现类似tcp的可靠性传输
- QUIC(https://www.cnblogs.com/zhoulujun/p/13060875.html)有自己的机制来保证传输的可靠性,当某个流发生丢包时,只会阻塞这个流,不会影响其他流
- TLS3升级成最新的1.3(https://zhuanlan.zhihu.com/p/44980381)版本,头部压缩算法也升级成Qpack
https建立一个连接要6次交互,QUIC合并成了3次
QUIC 是一个在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路复用的协议。参考: 陈皓.HTTP的前世今.酷壳CoolShell.https://coolshell.cn/articles/19840.html
QA
我看文中 TLS 和 SSL 没有做区分,这两个需要区分吗?
SSL 是洋文 “Secure Sockets Layer 的缩写,中文叫做「安全套接层」,将它标准化后名称改为TLS(Transport Layer Security),中文叫传输层安全协议为啥 ssl 的握手是 4 次
IP
基本认识
IP的作用是在复杂的网络环境将数据包发送给最终目的主机
和数据链路层的区别:mac实现直连的两个设备之前的通信,而ip则负责在没有之恋的两个网络之间进行通信传输
NAT: https://zhuanlan.zhihu.com/p/26992935
IP地址的基础知识
五类
ipv4是由32位的整数组成,每8位一组,共四组,五种类型的ip地址
主机号全1的指定某个网络下所有的主机,用于广播;全0指定某个网络
D类和E类地址是没有主机号的,所以不可用于主机ip,d类常被用于多播(将包发送给特定组内的所有主机),e类地址是预留的分类,暂时未使用
优缺点
IP分类的优点是:简单明了、选路(基于网络地址)简单
缺点是:同一网络下没有地址层次,缺少地址的灵活性;不能很好的与现实网络匹配;可以使用 CIDR 无分类地址解决
无分类地址 CIDR
没有分类地址的改变,32位被划分为两部分,网络号+主机号:a.b.c.d/x;或者子网掩码,它的另一个作用是划分子网
公有ip和私有ip
环回地址是同一台计算机上的程序之间进行网络通信时所使用的一个默认地址,127.0.0.1
IP分片与重组
数据链路的最大传输单元MTU是不相同的,之所以不相同是因为每个不同类型的数据链路的使用目的不同。
在分片传输中,一旦某个分片丢失,则会造成整个 IP 数据报作废,所以 TCP 引入了 MSS (最大分段大小)也就是在 TCP 层进行分片不由 IP 层分片,那么对于 UDP 我们尽量不要发送一个大于 MTU 的数据报文。
IPv6
v4 32位不够用了,v6是128位
亮点:
- IPv6 可自动配置,即使没有 DHCP 服务器也可以实现自动分配IP地址,真是便捷到即插即用啊。
- IPv6 包头包首部长度采用固定的值40字节,去掉了包头校验和,简化了首部结构,减轻了路 由器负荷,大大提高了传输的性能。
- IPv6 有应对伪造 IP 地址的网络安全功能以及防止线路窃听的功能,大大提升了安全性。
改进:
- 取消了首部校验和字段
- 取消了分片/重组相关字段,不允许路由器进行分片与分组,只能在源与目标主机上操作
- 取消选项字段
IP协议相关技术
DNS域名解析:将域名网址自动转换成IP
ARP:路由表确定IP数据包的下一跳,网络层的下一层是数据链路层,所以还要知道下一跳的mac地址;主机通过广播ARP请求,统一个链路中的所有设备收到ARP请求时,会拆开请求包的内容,如果ARP请求包中的目标ip地址和自己的意志,那么设备就将自己的mac地址塞入ARP的响应包返回给主机。对应关系会缓存起来。
与ARP相关的是RAPP协议。需要架设RARP服务器,需要ip的机器先发出询问,根据应答信息设置自己的ip地址。
DHCP用来动态获得ip地址,这不是发现注册吗???在DHCP交互过程中,全部用的UDP广播;当DHCP服务器和客户端不在同一个局域网内,路由器不会转发广播包,为了解决这个问题,就出现了DHCP中继代理,有了中继代理,对不同网段的IP地址也可以由同一个DBHCP服务器进行管理。
NAT主要进行网络地址转换,为了缓解IPv4地址耗尽的问题,NAT会讲同一区域的主机对外通信时,将私有IP换成公有IP地址。NAPT的作用时将网络地址和端口互换。NA(P)T依赖自己的转换表,有一下问题:
- 外部无法主动和NAT内部服务器进行连接,因为没有转换记录
- 转换表的生成和转换操作都会产生性能开销
- 通信过程中,如果NAT路由器重启了,所有的TCP连接都将被重置
解决办法:IPv6 + NAT穿透技术
ICMP(互联网控制报文协议)的主要功能包括:确认IP包是否成功送达目标地址、报告发动过程中IP包被废弃的原因、改善网络设置等。大致可以分为两大类:
- 用于诊断的查询信息,也就是查询报文类型
- 通知出错原因的错误信息,也就是差错报文类型
IGMP 是因特网组管理协议,工作在主机(组播成员)和最后一跳路由之间。
QA
ping是如何工作的?
ping基于ICMP协议工作,其工作过程为:
- 源主机首先会构建一个ICMP回送请求消息的数据包:类型为8+序号为1+发送时间
- ICMP协议将这个数据包连同目标地址一起交给IP层,本级IP地址作为源地址,协议字段设置为1表示ICMP地址,再加上一些其他的控制信息,构建一个IP数据包,再加入MAC头
- 目标主机收到数据帧时候,先检查MAC地址,如符合就接收,否则则丢弃;接受后将IP数据包从帧中提取出来,ip层检查后,将有用的信息提取后交给ICMP
- 目标主机会否件一个ICMP回送响应信息数据包,回送响应数据包的类型字段为0,序号是接收到的请求数据包中的序号,然后发送给源主机
在规定的时间内,没收到应答包,则说明目标主机不可达;接收到了说明可达。此时,源主机会检查,用当前时刻减去数据包最初的源主机上的时刻,就是ICMP数据包的延迟。
traceroute - 差错报文类型的使用
作用是:
- 故意设置特殊的 TTL,来追踪去往目的地时沿途经过的路由器。
- 故意设置不分片,从而确定路径的 MTU。
经典问题:输入网址后,期间会发生什么
- URL解析,生产http信息:请求报文
- URL对应的ip地址查询:域名服务器
- 协议栈+tcp:我理解是五层协议从上到下的过程来构成一个报文。tcp报文、三次握手、ip报文、mac地址获得
- 硬件设施:网卡(数字信号转换成电信号)、交换机(根据mac地址表查找mac地址,然后将信号发送给响应的端口)、路由器(去掉包开头的mac头部,解析ip地址,包上自己的mac地址在此进行传输
- 解析:五层协议由下向上
tcp相关问题
tcp连接:用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括socket、序列号和窗口大小成为连接
tcp和udp差别
TCP 和 UDP 区别:
- 连接
TCP 是面向连接的传输层协议,传输数据前先要建立连接。 UDP 是不需要连接,即刻传输数据。 - 服务对象
TCP 是一对一的两点服务,即一条连接只有两个端点。 UDP 支持一对一、一对多、多对多的交互通信 - 可靠性
TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按需到达。 UDP 是尽最大努力交付,不保证可靠交付数据。 - 拥塞控制、流量控制
TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。 - 首部开销
TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 20 个字节,如果使用了「选项」字段则会变长的的。UDP 首部只有 8 个字节,并且是固定不变的,开销较小。 - 传输方式
TCP 是流式传输,没有边界,但保证顺序和可靠。UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。 - 分片不同
TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输 层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完 数据,接着再传给传输层,但是如果中途丢了一个分片,则就需要重传所有的数据包,这样传输 效率非常差,所以通常 UDP 的报文应该小于 MTU。
应用场景:
由于 TCP 是面向连接,能保证数据的可靠性交付,因此经常用于: FTP 文件传输、 HTTP / HTTPS
由于 UDP 面向无连接,它可以随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于: 包总量较少的通信,如 DNS 、 SNMP 等;视频、音频等多媒体通信;广播通信
保活机制
定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP保活机制会开始作用,每个一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前tcp连接已经死亡,系统内核将错误信息通知给上层应用程序。
在linux中,
tcp_keepalive_time=7200:表示保活时间是 7200 秒(2小时),也就 2 小时内如果没有任何连接 相关的活动,则会启动保活机制
tcp_keepalive_intvl=75:表示每次检测间隔 75 秒;
tcp_keepalive_probes=9:表示检测 9 次无响应,认为对方是不可达的,从而中断本次的连接。
所以最少需要经过2小时11分15秒才可以发现一个死亡连接
为什么是三次握手
比较常见的回答是因为三次握手才能保证双方具有接收和发送的能力
- 阻止重复历史连接的初始化(例如旧的syn比新的syn先到达)
- 同步双方的初始序列号
- 避免资源浪费(例如客户段的syn阻塞了)
SYN攻击
攻击者短时间伪造不同的IP的SYN报文,server每接收到一个就进入SYN_RECV状态,但是server发出去的报文无法得到client的应答,时间一长就会沾满server的SYN的接收队列,使server不能为正常的用户服务
解决方式:修改Linux参数(p129)
重传机制
超时重传:设置一个定时器,超出指定时间没有收到对方的ACK报文,就重发该数据;(RTO的值应略大于RTT的值)
快速重传:当收到三个相同的ACK报文时,会在定时器过期之前,重传丢失的报文段;缺点是不清楚重传哪些报文
SACK:在tcp的头部选项字段中加一个sack的东西,将缓存的地图发送给发送方,这样发送方就知道哪些数据收到了,哪些数据没收到,就可以只重传丢失的数据
D-SACK:使用sack来告诉发送方有哪些数据被重复接收了
滑动窗口
一来一往效率低下,于是创建一个窗口,可以一下子发出去好多包,根据收到的响应的报文,滑动窗口
流量控制
发送方不能无脑的发数据给接收方,要考虑接收方的处理能力。
拥塞控制
在网络出现拥堵时,如果继续发送大量的数据包,可能会导致数据包时延、丢失等,这是tcp就会重传数据,但是一重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这种情况就会进入恶性循环被不断放大。于是又了拥塞控制,避免发送方的数据填满整个网络。
发送方没有在规定的时间内接收到ack应答报文,也就是发生了超时重传,就会认为网络出现了拥塞。这时候发送窗口大小=min(拥塞窗口,接收窗口)。
拥塞控制的四个算法
- 慢启动:刚完成tcp连接的时候,有一个慢启动的过程(173)。规则:当发送方每收到一个ACK,拥塞窗口大小就会加1,呈指数式增长。但是有一个慢启动门限的状态变量ssthresh,cwnd
=时,就会使用拥塞避免算法 - 拥塞避免:规则:每当收到一个ACK时,cwnd增加1/cwnd
- 拥塞发生:超时重传(ssthresh = cwmd/2,cwnd = 1)、快速重传(ssthresh = cwnd,cwnd = cwnd/2)
- 快速恢复:cwnd = sshresh+3,重传丢失的数据包,如果再收到重复的ACK,那么cwnd增加1;如果收到洗数据的ACK后,把cwnd设置为拥塞发生时的ssthresh
实战篇(p179)
这篇只写结论,具体推理过程请查看原文档。
分析网络的两大利器:tcpdump 和 Wireshark
TCP 第一次握手的 SYN 丢包了,会发生了什么?
客户端在一直没收到服务短的ACK时,会一直超时重传5(这个值可以设置)次。每次的RTO超时时间是不同的,都是指数(翻倍)上涨,超过最大重传次数之后,客户端不会再发送SYN包。
TCP 第二次握手的 SYN、ACK 丢包了,会发生什么?
客户端会超时重传SYN包,服务端也会超时重传SYN+ACK包,重传次数根据系统设置,默认是5
TCP 第三次握手的 ACK 包丢了,会发生什么?
服务端没收到第三次握手的ACK,会重传SYN+ACK,超过最大重试次数后,服务端会断开tcp连接
客户端则有两种情况:
- 如果客户端没发送数据包,一直处于ESTABLISHED状态,然后经过2小时11分钟15秒才发现死亡连接,于是客户端就会断开连接。
- 如果客户端发送了数据包,一直没收到服务端对该数据包的确认报文,则一直重传该数据包,直到重传次数超过tcp_retries2值后,客户端会断开连接
TCP快速建立连接
一般建立tcp连接需要三次握手,在快速建立连接的情况下,只需要两次握手即可。这个是TCP Fast Open。过程是:在第二次的握手时,服务器会在SYN+ACK的基础上再加一个cookie,客户端收到后,在下次请求的时候,在SYN包中带上cookie发送给服务端,就提前可以跳过三次握手的过程
tcp半连接队列和全连接队列满了会发生什么?
半连接队列(SYN队列):收到SYN的连接会存储到这里
全连接队列(accept队列):收到客户端发来的SYN确认报文后,将连接从半连接队列移除,然后创建新的完全连接,然后添加到accept队列
当全连接队列满了之后,后续的请求就会被丢弃。在linux中可以指定用什么策略回应客户端。丢弃连接只是linux的默认行为,我们还可以像客户端发送RST复位报文,告诉客户端连接已经建立失败。
那么如何增大全连接队列的呢?TCP 全连接队列的最大值取决于 somaxconn 和 backlog 之间的最小值,也就是min(somaxconn, backlog)
在前面我们在分析 TCP 第一次握手(收到 SYN 包)时会被丢弃的三种条件:
- 如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;
- 若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于 1 个,则会丢弃;
- 如果没有开启 tcp_syncookies,并且 max_syn_backlog 减去 当前半连接队列长度小于 (max_syn_backlog >> 2),则会丢弃;
tcp_syncookies 是这么做的:服务器根据当前状态计算出一个值,放在己方发出的 SYN+ACK 报文中发出,当客户端返回 ACK 报文时,取出该值验证,如果合法,就认为连接建立成功。