- 很难找到一款完全不需要网络的应用,即使是单机应用,也会存在数据上报、广告等各种各样的网络请求
网络基础
Http & Https
定义:
- https:Hypertext Transfer Protocol over Secure Socket Layer 超文本传输协议的安全套接字层
- http:一种详细规定了浏览器和万维网服务器之间互相通信的规则
区别:
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的SSL/TLS加密
传输协议(在 HTTP 与 TCP 之间)。(SSL/TSL 的常见开源实现是 OpenSSL) - http和https使用的是完全不同的连接方式,默认端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、
身份认证的网络协议,比http协议安全。 - 写法上的区别是前缀的不同,客户端处理的方式也不同;
SSL(Secure Sockets Layer)安全套接层
- SSL 位于传输层与应用层之间,它是一个子层,作用主要有两点:
- 数据安全(保证数据不会被泄漏)与数据完整(保证数据不会被篡改);
- 对数据进行加密后传输;
https目的:
- 提供对网站服务器的身份认证,保护交换数据的隐私和完整性;
HTTPS 解决的问题:
- 信任主机问题(从CA申请证书);
- 防止通信过程中的数据的泄密和被篡改;
https实现原理:
- 客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
- Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
- 客户端的浏览器与Web服务器开始协商SSL连接的安全等级(交换协议版本号),也就是信息加密的等级。
- 客户端的浏览器根据双方同意的安全等级,建立临时会话密钥,然后利用网站的公钥将会话密钥加密,
并传送给网站。 - Web服务器利用自己的私钥解密出会话密钥。
- Web服务器利用会话密钥加密与客户端之间的通信。
https加密原理
- 相比较对称加密而言,非对称加密安全性更高,但是加解密耗费的时间更长,速度慢。
CA证书:
其实就是数字证书,是由 CA 机构颁发的,包括证书的颁发机构、版本, 使用者,公钥,有效时间,数字签名 Hash 值和签名 Hash 算法;
客户端如何校验CA证书
CA 证书中的 Hash 值,其实是用证书的私钥进行加密后的值(证书的私钥不在 CA 证书 中)。然后客户端得到证书后,利用证书中的公钥去解密该 Hash 值,得到 Hash-a ;然 后再利用证书内的签名 Hash 算法去生成一个 Hash-b 。最后比较 Hash-a 和 Hash-b 这 两个的值。如果相等,那么证明了该证书是对的,服务端是可以被信任的;如果不相等,那 么就说明该证书是错误的,可能被篡改了,浏览器会给出相关提示,无法建立起 HTTPS 连 接。除此之外,还会校验 CA 证书的有效时间和域名匹配等。
HTTPS中的SSL握手建立过程
- 客户端和服务端建立 SSL 握手,客户端通过 CA 证书来确认服务端的身份;
- 互相传递三个随机数,之后通过这随机数来生成一个密钥;
- 互相确认密钥,然后握手结束;
- 数据通讯开始,都使用同一个对话密钥来加解密;
(简而言之,用非对称加密算法生成对称加密的秘钥,用对称加密算法加密通信内容)
分层:
OSI七层模型(物数网传会表应)
- 应用层: 为计算机用户提供接口和服务。
- 表示层: 数据处理:编解码、加解密等等。
- 会话层: 管理(建立、维护、重连)通信会话。
- 传输层: 管理端到端的通信连接。
- 网络层: 数据路由:决定数据在网络中的路径。
- 数据链路层: 管理相邻节点之间的数据通信。
- 物理层: 数据通信的光电物理特性。
TCP/IP 四层模型
- 应用层:包括OSI中的会表应三层,HTTP,FTP,SMTP,POP3,NFS、DNS等协议都属于应用层;
- 传输层,TCP/UDP协议属于传输层
- 网络层:IP协议属于网络层
- 网络接口层:包括OSI中的物数两层,
HTTP(应用层)》》TSL/SSL(安全层)》》TCP(传输层)》》IP(网络层)》》网络接口(数据链路层)
DNS(Domain Name System) 域名系统服务
- 通过把没有规则的点分十进制 IP 地址转换为可以理解的一些域名(域名通过 DNS 服务可以被转换成 IP 地址。);
域名:
- 可以分为顶级域、二级域、三级域…,例如:www.taobao.com => - 三级域.二级域.顶级域。
DHCP(Dynamic Host Configuratin Protocol) 动态主机设置协议
- 网络管理员只需配置一段共享的 IP 地址,每一台新接入的机器都可以通过 DHCP 来这个共享的 IP 地址里面申请 IP 地址,就可以自动配置。等用完还回去其它机器也能使用;
- DHCP 是一个局域网协议,是应用 UDP 协议的应用层协议;
为什么 TCP 要经过三次握手,四次挥手
三次握手:
- 第一次握手:建立连接。客户端发送连接请求报文段,将 SYN 位置为 1,Sequence Number为 x;然后,客户端进入 SYN_SEND 状态,等待服务器的确认。
- 第二次握手:服务器收到 SYN 报文段。服务器收到客户端的 SYN 报文段,需要对这个 SYN 报文段进行确认,设置 Acknowledgment Number 为 x+1(Sequence Number+1);同时,自己自己还要发送 SYN 请求信息,将 SYN 位置为 1,Sequence Number 为 y;服务器端将上述所有信息放到一个报文段(即 SYN+ACK 报文段)中,一并发送给客户端,此时服务器进入 SYN_RECV 状态;
- 第三次握手:客户端收到服务器的 SYN+ACK 报文段。然后将 Acknowledgment Number设置为 y+1,向服务器发送 ACK 报文段,这个报文段发送完毕以后,客户端和服务器端都进入 ESTABLISHED 状态,完成 TCP 三次握手。
四次挥手
- 第一次分手:主机 1(可以使客户端,也可以是服务器端),设置 Sequence Number 和Acknowledgment Number,向主机 2 发送一个 FIN 报文段;此时,主机 1 进入 FIN_WAIT_1状态;这表示主机 1 没有数据要发送给主机 2 了;
- 第二次分手:主机 2 收到了主机 1 发送的 FIN 报文段,向主机 1 回一个 ACK 报文段,Acknowledgment Number 为 Sequence Number 加 1;主机 1 进入 FIN_WAIT_2 状态;主机 2 告诉主机 1,我“同意”你的关闭请求;
- 第三次分手:主机 2 向主机 1 发送 FIN 报文段,请求关闭连接,同时主机 2 进入 LAST_ACK状态;
- 第四次分手:主机 1 收到主机 2 发送的 FIN 报文段,向主机 2 发送 ACK 报文段,然后主机1 进入 TIME_WAIT 状态;主机 2 收到主机 1 的 ACK 报文段以后,就关闭连接;此时,主机1 等待 2MSL 后依然没有收到回复,则证明 Server 端已正常关闭,那好,主机 1 也可以关闭连接了。(MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃);
- “三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。主要目的防止 server 端一直等待,浪费资源。换句话说,即是为了保证服务端能收接受到客户端的信息并能做出正确的应答而进行前两次(第一次和第二次)握手,为了保证客户端能够接收到服务端的信息并能做出正确的应答而进行后两次(第二次和第三次)握手。
- “四次挥手”原因是因为 tcp 是全双工模式,接收到 FIN 时意味将没有数据再发来,但是还是可以继续发送数据。
TCP 在三次握手的时候,IP 层和 MAC层在做什么?
- TCP 每发送一个消息,都会带着 IP 层和 MAC 层。因为 TCP 每发送一个消息,IP 层和 MAC 层的所有机制都要运行一遍。
TCP 和 UDP 的区别?
- TCP面向连接,UDP是无连接(即发送数据之前不需要建立连接);
- 对系统资源的要求(TCP 较多,UDP 少);
- UDP 程序结构较简单,不会对数据报进行任何的处理,即不合并,也不拆分数据,直接将应用层数据塞进报文里面。
- UDP 通常用于多媒体信息分发,即视频、语音、实时信息 等等。而 TCP 通常用于可靠信息的传输,应用场景包括金融交易、可靠通信、MQ 等等 ;
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;
UDP没有拥塞控制,尽最大努力交付,不管网络是否拥塞,它都会把数据给交付出去,但不保证可靠交付 - UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
- 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
- TCP是全双工通信:两个设备在连接时,它们都可以同时地发送数据与接收数据。
- TCP是面向字节流的协议(可能出现黏包问题),UDP面向报文传输
- TCP 首部开销20字节;UDP 的首部开销小,只有 8 个字节。
TCP 协议的可靠传输
- 滑动窗口
- 累积确认
- 选择重传
TCP 协议的流量控制
- 流量控制指的是 让发送方发送速率不要太快。TCP 使用了滑动窗口来实现流量控制。
- 滑动窗口: 接收方可以调整滑动窗口的大小来控制发送方发送数据的效率。
- 坚持定时器: 使用滑动窗口进行流量控制的时候设置:当接收到窗口为0的消息,则启动坚持定时器;坚持定时器每隔一段时间发送一个窗口探测报文;
TCP 协议的拥塞控制
- 不同于流量控制考虑的是点对点的通信量的控制,拥塞控制考虑的是整个网络,是一个全局性的考虑。
- 慢启动算法:由小到大逐渐增加发送数据量;每收到一个报文确认,就加一;超过慢启动阈值(ssthresh) 则不再增长。
- 拥塞避免算法:维护一个拥塞窗口的变量;只要网络不拥塞,就试探着将拥塞窗口调大。
- TCP 的拥塞控制在前期使用了 慢启动 算法对窗口大小进行指数增长,直到超过慢启动阈值(ssthresh)则不再增长,后续则启动拥塞避免算法对窗口进行线性增长。
TCP 协议的四个定时器
- 超时定时器;
- 坚持定时器;
- 时间等待定时器;
- 保活定时器:
TCP可靠传输原理实现
- 确认和重传:接收方收到报文后就会进行确认,发送方一段时间没有收到确认就会重传。
- 数据校验。
- 数据合理分片与排序: TCP 会对数据进行分片,接收方会缓存为按序到达的数据,重新排序后再提交给应用层。
- 流程控制:当接收方来不及接收发送的数据时,则会提示发送方降低发送的速度,防止包丢失。
- 拥塞控制:当网络发生拥塞时,减少数据的发送。
(http://blog.chinaunix.net/uid-26275986-id-4109679.html)
IP 协议
- 物理设备通过使用 IP 协议,屏蔽了物理网络之间的差异;
作用
- IP 协议 使得复杂的实际网络变为一个虚拟互连的网络;
- IP 协议 使得网络层可以屏蔽底层细节而专注网络层的数据转发;
- IP 协议 解决了在虚拟网络中数据报传输路径的问题;
IP 地址
- 每一个唯一的网络设备都有一个唯一的 IP 地址。不同于 MAC 地址是不可改变的,IP 地址会根据当前设备所连接的网络环境的变化而发生变化。
MAC 地址与 IP 地址的区别
- 数据帧每一跳的 MAC 地址都在变化,而IP 数据报每一跳的 IP 地址始终不变。
- IP 地址具有远程定位功能,而 MAC 地址更像是身份证号,它的唯一性是为了组网时可以不用担心不同的网卡在一个网络里会产生冲突,从硬件角度保证不同的网卡有不同的标识。
- 相比于 IP 地址,MAC 地址的通信范围比较小,局限在一个子网里。例如:从 192.168.0.1/24 访问 192.168.0.9/24 是可以用 MAC 地址的。
ARP(Address Resolution Protocol)地址解析协议
- 将网络层 IP 32位地址转换为数据链路层 MAC 48位地址。
- ARP 协议被直接封装在了数据链路层中的数据帧里面的。
RARP(Reverse Address Resolutioni Protocol)逆地址解析协议
- 将数据链路层 MAC 48位地址转换为网络层 IP 32位地址
- 除了类型 8035 标识为 RARP 协议,其它内容与 ARP 协议类似。
网络地址转换 NAT(Network Address Translationn) 技术
- 不改变 IP 地址的网关,我们称为转发网关;改变 IP 地址的网关,我们称为 NAT 网关。
- 使用 NAT ,它用于多个主机通过一个公有 IP 访问互联网的私有网络,并减缓了 IP 地址的消耗,但是增加了网络通信的复杂度。
- 为什么要使用 NAT?
- IPv4 最多只有40+亿个 IP 地址。
- 早期 IP 地址的不合理规划导致 IP 号浪费。
内网地址
三类内网地址:
- A 类:10.0.0.0~10.255.255.255(支持千万数量级设备)。
- B 类:172.16.0.0~172.31.255.255(支持百万数据级设备)。
- C 类:192.168.0.0~192.168.255.255(支持万数量级设备)。
ICMP(Internet Control Message Protocol)协议
- ICMP 协议主要是用于 辅助 IP 协议发送与接收数据的,它可以报告错误信息或异常情况。
应用:使用 Ping 命令对网络故障进行排查
- ping 回环地址 127.0.0.1,不通,说明计算机使用的协议栈有问题,需要重装系统或协议栈。
- Ping 网关地址(路由地址),内网 ping 192.168.0.1/ 192.168.1.1,通,说明本机到路由器的地址是通的。不通,则说明 WIFI、网线是有问题的。
- Ping 远端地址 ping www.wanandroid.com,不通,则说明家中到 ISP 的网络之间是有故障的。这个时候就要从电信、联通、移动等 ISP 来排查问题了。
路由
- 路由表: 包括了目的IP地址与下一跳IP地址的映射关系;
GET 和 POST 的区别
- get参数通过url传递,post放在request body中。
- get请求在url中传递的参数是有长度限制的,而post没有。
- get比post更不安全,因为参数直接暴露在url中,所以不能用来传递敏感信息。
- get请求只能进行url编码,而post支持多种编码方式。
- get请求会浏览器主动cache,请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。
- GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
无线网络
- 网络的分类:按作用范围分为广域网,城域网,局域网;按使用者可分为公用网络,专用网络;按传输介质分为有线网络,无线网络;
- 有线通信:在实体物质上传播,使用铜线、光纤等有线介质
- 无线通信:利用电磁波进行通信,常用的无线网络类型:WiFi、蜂窝网络、蓝牙、NFC;
- 无线网络的瓶颈:单条光纤最大速度已达到了26Tbps,目前主流的移动通信标准,4G LTE,理论速率只有150Mbps(不包括载波聚合)。
这个和有线是完全没办法相比的,所以,5G如果要实现端到端的高速率,重点是突破无线这部分的瓶颈;
电磁波
- 电磁波的功能特性,是由它的频率决定的。不同频率的电磁波,有不同的属性特点,从而有不同的用途。例如,高频的γ射线,具有很大的杀伤力,可以用来治疗肿瘤。
- 电波和光波,都属于电磁波,目前主要使用电波进行通信。当然,光波通信也在崛起,例如LiFi;电波的频率资源是有限的,为了避免干扰和冲突,我们在电波这条公路上进一步划分车道,分配给不同的对象和用途。目前全球主流的4G LTE技术标准,属于特高频和超高频。
无线通信的频率
- 先说一个公式:c=λv, 即 光速=波长×频率,无论是1G、2G、3G,还是4G、5G,万变不离其宗,全部都是在它身上做文章;
- 随着1G、2G、3G、4G的发展,使用的电波频率是越来越高的,主要是因为,频率越高,能使用的频率资源越丰富。频率资源越丰富,能实现的传输速率就越高。(频率资源就像车厢,越高的频率,车厢越多,相同时间内能装载的信息就越多。)
- 既然,频率高这么好,你一定会问:“为什么以前我们不用高频率呢?”,原因很简单,不是不想用,是用不起。电磁波的显著特点就是频率越高,波长越短,越趋近于直线传播(绕射能力越差),在传播介质中的衰减也越大,移动通信如果用了高频段,那么它最大的问题,就是传输距离大幅缩短,覆盖能力大幅减弱。相反的,频率越低,网络建设就越省钱,竞争起来就越有利。这就是为什么,这些年,电信、移动、联通为了低频段而争得头破血流。
- 5G的一大技术特点就是 毫米波, 覆盖同一个区域,需要的5G基站数量,将大大超过4G。
基站
- 基站有两种,微基站和宏基站。看名字就知道,微基站很小(城区和室内常见,5G时代更将随处可见),宏基站很大(室外常见,建一个覆盖一大片))
- 那么多基站在身边,会不会对人体造成影响?其实,和传统认知恰好相反,事实上,基站数量越多,辐射反而越小!(基站小,功率低,对大家都好。如果只采用一个大基站,离得近,辐射大,离得远,没信号,反而不好。)(频率:电波<过度频带<红外线<可见光<紫外线<x射线<γ射线,可见电波的最高频率仍小于可见光频率)
天线去哪了
- 以前大哥大都有很长的天线,早期的手机也有突出来的小天线,为什么现在我们的手机都没有天线了,其实,我们并不是不需要天线,而是我们的天线变小了,根据天线特性,天线长度应与波长成正比,大约在1/10~1/4之间,手机的通信频率越来越高,波长越来越短,天线也就跟着变短啦;
Massive MIMO(多天线技术)
- MIMO就是“多进多出”(Multiple-Input Multiple-Output),多根天线发送,多根天线接收,在LTE时代,我们就已经有MIMO了,但是天线数量并不算多,只能说是初级版的MIMO,到了5G时代,继续把MIMO技术发扬光大,现在变成了加强版的Massive MIMO(Massive:大规模的;5G是毫米波通信,天线也变成毫米级,手机里就可以集成很多根天线);
千兆级 LTE
- 指的是蜂窝网络在理论上速度可以达到光纤级别的 1Gbps(125MB/s)。虽然基于 4G 标准,但通过MIMO(多输入多输出)、使用载波聚合的LAA等技术,现在已经发展到千兆级 LTE。
Link Turbo
- 手机厂商为了提升用户的网络体验,也会做各种各样的定制优化,华为推出的Link Turbo 网络聚合加速技术就是其中比较硬核的一种“黑科技”。
- 从硬件角度来说,WiFi 和蜂窝网络属于基带芯片的不同模块,我们可以简单的把它们理解为类似双网卡的情形。所谓的 Link Turbo 就是在使用 WiFi 的同时使用移动网络加速。双通道的技术以前也有,侦测到 WiFi 网络不稳定时,自动切换到移动网络,而 Link Turbo 硬核的地方在于可以同时使用两条通道传输数据,而且支持 TCP 与 UDP。
网络I/O
Socket 描述符(socket fd)
- 一切皆文件”,Linux 内核会把所有外部设备都看作一个文件来操作。在网络 I/O 中系统对一个 Socket 的读写也会有相应的描述符,称为 socket fd;
同步
- 同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致
异步
- 异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。
- 异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息通知时被阻塞
阻塞
- 是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务。函数只有在得到结果之后才会返回。
非阻塞
- 非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
小明的故事
- 同步阻塞:小明一直盯着下载进度条,到 100% 的时候就完成。
- 同步非阻塞:小明提交下载任务后就去干别的,每过一段时间就去瞄一眼进度条,看到 100% 就完成。
- 异步阻塞:小明换了个有下载完成通知功能的软件,下载完成就“叮”一声。不过小明仍然一直等待“叮”的声音
- 异步非阻塞:仍然是那个会“叮”一声的下载软件,小明提交下载任务后就去干别的,听到“叮”的一声就知道完成了
网络I/O 模型
- 《UNIX 网络编程》中将 UNIX 网络 I/O 模型分为以下五种(前四种均为同步):
1. 阻塞I/O
- 阻塞I/O:用户空间的应用程序执行一个系统调用,这会导致应用程序阻塞,什么也不干,直到数据准备好,并且将数据从内核复制到用户进程,最后进程再处理数据,在等待数据到处理数据的两个阶段,整个进程都被阻塞。不能处理别的网络IO。
2. 非阻塞I/O
- 非阻塞I/O:非阻塞的recvform系统调用调用之后,进程并没有被阻塞,内核马上返回给进程,如果数据还没准备好,此时会返回一个error。进程在返回之后,可以干点别的事情,然后再发起recvform系统调用。重复上面的过程,循环往复的进行recvform系统调用。这个过程通常被称之为轮询。轮询检查内核数据,直到数据准备好,再拷贝数据到进程,进行数据处理。
3. 多路复用I/O
- 由于同步非阻塞方式需要不断主动轮询,轮询占据了很大一部分过程,轮询会消耗大量的CPU时间,而 “后台” 可能有多个任务在同时进行,人们就想到了循环查询多个任务的完成状态,只要有任何一个任务完成,就去处理它。如果轮询不是进程的用户态,而是有人帮忙就好了。那么这就是所谓的 “IO 多路复用”。UNIX/Linux 下的 select、poll、epoll 就是干这个的(epoll 比 poll、select 效率高,做的事情是一样的)。
4. 信号驱动式I/O
- 首先我们允许Socket进行信号驱动IO,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。
5. 异步I/O
- 相对于同步IO,异步IO不是顺序执行。用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO两个阶段,进程都是非阻塞的。
网络性能评估与优化
性能评估
延迟与带宽
- 延迟:数据从信息源发送到目的地所需的时间。
- 带宽:逻辑或物理通信路径最大的吞吐量。
- 延迟和带宽涉及的因素也非常多,例如信号的强度、附近有没有基站、距离有多远等;还跟使用的网络制式,正在使用 3G、4G 还是 5G 网络有关,并且网络的拥塞情况也会产生影响
- 不同的应用对延迟和带宽的侧重点可能不太一样。对于直播类应用或者“王者荣耀”来说,延迟会更重要一些;对腾讯视频、爱奇艺这种点播的应用来说,带宽会更加重要一些。
不同网络制式的带宽与延迟参考值
网络制式 带宽(下行/上行) 延迟
2.75 G 384KB/48KB 600~700ms
3 G 7MB/2MB 150~400ms
4 G 128MB/56MB 40~50ms
5G >100MB/>50MB <10ms
弱网络
- 高延迟、低带宽的网络场景也就是我们常说的“弱网络”
特点:
- 丢包率高:信号问题,用户过多,误码包,用户移动,基站切换
- 误码率高:环境电波,用户距离远
- 不稳定的延迟:用户数量,信令分配,丢包,误码包
- 不稳定的带宽:基站距离,用户数量,拥塞控制
性能测量
- 吞吐量:网络接口接收和传输的每秒字节数。
- 延迟:系统调用发送 / 接收延时、连接延迟、首包延迟、网络往返时间等。
- 连接数:每秒的连接数。
- 错误:丢包计数、超时等。
网络性能分析工具
- strace: 跟踪Socket相关的系统调用
- netstat:多种网络栈和接口统计信息
- ifconfig:接口配置
- ip:网络接口统计信息
- ping:测试网络连通性
- traceroute:测试网络路由
- tcpdump:网络数据包嗅探器
- 抓包工具Wireshark,Fiddler,Charles等:图形化的网络数据报检查
- 如果你对 Linux 底层更加熟悉,可以直接查看 /proc/net,它里面包含了许多网络统计信息的文件。例如Android 的TrafficState接口就是利用 /proc/net/xt_qtaguid/stats 和 /proc/net/xt_qtaguid/iface_stat_fmt 文件来统计应用的流量信息。
TPC 优化
- 因特网有两个核心协议:IP 和 TCP,IP负责联网主机之间的路由选择和寻址;TCP负责在不可靠的传输信道之上提供可靠的抽象层。而 TCP/IP 也常被称为 “因特网协议套件”(Internet Protocol Suite)。
1. 重用连接
- 三次握手带来的延迟使得每创建一个新 TCP 连接都要付出很大代价。而这也决定了提高 TCP 应用性能的关键,在于想办法重用连接。
TFO(TCP Fast Open,TCP快速打开)
- TFO 致力于减少新建 TCP 连接带来的性能损失。但却只能在某些情况下有效。比如,随同 SYN 分组一起发送的数据净荷有最大尺寸限制、只能发送某些类型的 HTTP 请 求,以及由于依赖加密 cookie,只能应用于重复的连接。
2. 拥塞预防及控制
流量控制
- (滑动窗口)为实现流量控制,TCP 连接的每一方都要通告自己的接收窗口(rwnd),其中包含能够保存数据的缓冲区空间大小信息。这个过程贯穿于每个 TCP 连接的整个生命周期: 每个 ACK 分组都会携带相应的最新 rwnd 值,以便两端动态调整数据流速,使之适应发送端和接收端的容量及处理能力。
慢启动
- 由小到大逐渐增加发送数据量;每收到一个报文确认,就加一;超过慢启动阈值(ssthresh) 则不再增长。
拥塞预防
- 拥塞预防算法把丢包作为网络拥塞的标志,即路径中某个连接或路由器已经拥堵了,以至于必须采取删包措施。因此,必须调整窗口大小,以避免造成更多的包丢失, 从而保证网络畅通
TCP PRR(Proportional Rate Reduction,比例降速)
- 最初,TCP 使用 AIMD(Multiplicative Decrease and Additive Increase,倍减加增) 算法,即发生丢包时,先将拥塞窗口减半,然后每次往返再缓慢地给窗口增加一 个固定的值。后来,出现了 PRR(Proportional Rate Reduction,比例降速),它是 RFC 6937 规定的一个新算法,其目标就是 改进丢包后的恢复速度。使用它因丢包造成的平均连接延迟减少了 3%~10%。此外,PRR 现在也是 Linux 3.2+ 内核默认的拥塞预防算法。
客户端优化
- 少发或者不发网络情况(请求合并):消除不必要的数据传输本身就是很大的优化。比如,减少下载不必要的资源,或者通过压缩算法把要发送的比特数降到最低。
- 使用 CDN,让通信距离更短:通过在不同的地区部署服务器,把数据放到接近客户端的地方,可以减少网络往返的延迟,从而显著提升 TCP 性能。
- 重用 TCP 连接:把慢启动和其他拥塞控制机制的影响降到最低。
UDP 优化
- UDP 的特色在于它所省略的那些功能:连接状态、握手、重发、重组、重排、拥塞控制、拥塞预防、流量控制,甚至可选的错误检测,统统没有。
在 RFC 5405 中,对设计单播 UDP 应用程序给出了很多设计建议(WebRTC 协议是下述规则的设计典范),如下所示:
1. 必须容忍各种因特网路径条件;
2. 应该控制传输速度;
3. 应该对所有流量进行拥塞控制;
4. 应该使用与 TCP 相近的带宽;
5. 应该准备基于丢包的重发计数器;
6. 应该不发送大于路径 MTU 的数据报;
7. 应该处理数据报丢失、重复和重排;
8. 应该足够稳定以支持 2 分钟以上的交付延迟;
9. 应该支持 IPv4 UDP 校验和,必须支持 IPv6 校验和;
10. 可以在需要时使用 keep-alive(最小间隔 15 秒)。
TLS(Transport Layer Security,传输层安全)
- IETF 在标准化 SSL 协议时,将其改名为 Transport Layer Security (TLS,传输层安全)。很多人会混用 TLS 和 SSL,但严格来讲它们并不相 同,因为它们指代的协议版本不同。
- TLS 也可以实现在 UDP 之上,DTLS(Datagram Transport Layer Security,数据报传输层安全)(RFC 6347)就旨在以 TLS 协议为基础,同时兼顾数据报交付模式并提供类似的安全保障。
TLS 协议的目标是为在它之上运行的应用提供三个基本服务:
- 加密:混淆数据的机制。
- 身份验证:验证身份标识有效性的机制。
- 数据完整性:检测消息是否被篡改或伪造的机制。
TLS 优化
- 尽早完成握手
- 使用会话缓存与无状态恢复
- TLS 记录大小(小记录会造成浪费,大记录会导致延迟)
- 证书链的长度:如果证书链长度超过了 TCP 的初始拥塞窗口,那我们无意间就会让握手多了一次往返:证书长度超过拥塞窗口,从而导致服务器停下来等待 客户端的 ACK 消息。(解决方法:增大拥塞窗口,减少证书大小)
- OCSP 封套:服务器可以在证书链中包含(封套)证书颁发机构的 OCSP 响应,让浏览器跳过在线查询。把查询 OCSP 操作转移到服务器可以让服务器缓存签名的 OCSP 响应,从而节省很多客户端的请求。
- HTTP 严格传输安全:一种安全策略机制,让服务器通过简单的 HTTP 首部(如 Strict-Transport-Security: max-age=31536000) 对适用的浏览器声明访问规则。
移动端优化
何为网络库
- 实际开发中,我们很少会直接操作底层的网络接口,而是使用网络库;
网络库的核心作用
- 統一編程接口:简单易用,便于统一进行策略管理,流解析(JSON,XNML等)
- 全局网络控制:统一的网络调度,流量监控,容灾管理(跳维护页),控制日志输出,增加拦截器等
- 高性能:
网络库对比
xUtils:
- 这个框架非常全面,可以进行网络请求,可以进行图片加载处理,可以数据储存,还可以对view进行注解,使用这个框架非常方便,但是缺点也是非常明显的,使用这个项目,会导致项目对这个框架依赖非常的严重,一旦这个框架出现问题,那么对项目来说影响非常大的。
Volley:
- Volley是Google官方出的一套小而巧的异步请求库,该框架封装的扩展性很强,支持HttpClient、HttpUrlConnection,甚至支持OkHttp,而且Volley里面也封装了ImageLoader,所以如果你愿意你甚至不需要使用图片加载框架,不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用,稍复杂点的需求还是需要用到专门的图片加载框架。Volley也有缺陷,比如不支持post大数据,所以不适合上传文件。不过Volley设计的初衷本身也就是为频繁的、数据量小的网络请求而生。
- 优势在于封装的更好
Retrofit:
- Retrofit是Square公司出品的默认基于OkHttp封装的一套RESTful网络请求框架。Retrofit的封装可以说是很强大, 里面涉及到一堆的设计模式,可以通过注解直接配置请求,可以使用不同的http客户端,虽然默认是用http ,可以使用不同Json Converter 来序列化数据,同时提供对RxJava的支持,使用Retrofit + OkHttp + RxJava + Dagger2可以说是目前比较潮的一套框架,但是需要有比较高的门槛。
- Retrofit解耦的更彻底
- 默认使用OkHttp,性能上也要比Volley占优势
okHttp:
- okHttp针对Java和Android程序,封装的一个高性能的http请求库,支持同步,异步,而且封装了线程池,封装了数据转换, 封装了参数的使用,错误处理等。API使用起来更加的方便。但是我们在项目中使用的时候仍然需要自己在做一层封装,这样才能使用的更加的顺手。
- OkHttp的优势在于性能更高
- DNS管理:支持DNS缓存,支持对接自己的HTTPDNS
- 并发模型:使用多线程实现并发,实际执行线程数受队列机制控制,最大64,单个Host限制5个;
- 连接管理:对于http连接,每个域名最多缓存5个连接,默认KeepTime是5分钟,对于HTTP/2连接,每个域名都共用一个H/2连接;
- IO模型:阻塞Socket,使用OKio包装Socket进行流读写;
- 网络质量监控:默认不支持,有一些第三方插件;
- 长连接:默认不支持;
- 跨平台:java实现,无法跨平台;
- 二次开发:容易;
- 协议支持:HTTP/1.1,HTTP/2.0,TLS1.1,TLS1.2
Chromium 的Cronet:
- 蘑菇街、头条、UC 浏览器都在 Chromium 网络库上做了二次开发;
- DNS管理:支持DNS缓存,支持对接自己的HTTPDNS;
- 并发模型:每个host对应一条线程,每个线程可以创建6个非阻塞socket请求网络;
- 连接管理:对于HTTP连接每个域名最多缓存6个连接,对于HTTP/2连接,每个域名都共用一个H/2连接;
- IO模型:epll+非阻塞socket;
- 网络质量监控:Predictor用于收集使用数据并预测网络行为,NQE提供当前网络质量评估;
- 长连接:默认不支持;
- 跨平台:c++实现,可以跨平台;
- 二次开发:实现复杂,不容易扩展;
- 协议支持:HTTP/1.1,HTTP/2.0,QUIC,TLS1.1,TLS1.2,TLS1.3
微信 Mars:
- 在弱网络方面做了大量优化,拼多多、虎牙、链家、美丽说这些应用都在使用 Mars;
- DNS管理:支持DNS缓存,支持对接自己的HTTPDNS;
- 并发模型:每个短连都是一个线程,没有线程限制;
- 连接管理:支持复合连接,没有连接管理;
- IO模型:epll+非阻塞socket;
- 网络质量监控:SDT模块支持网络侦测与诊断;
- 长连接:默认支持;
- 跨平台:c++实现,可以跨平台;
- 二次开发:相比Cronet简单一些;
- 协议支持:信令网络,只支持TCP;
- 查看更多:https://github.com/Tencent/mars/wiki
大网络平台
- 阿里的ACCS、蚂蚁的mPaaS、携程的网络服务都是公司级的网络中台服务,这样所有的网络优化可以让整个集团的所有接入应用受益。
为何优化
- 等待网络是我们 App 最大的性能瓶颈,直接影响到用户体验,用户粘性,用户忠诚度,以及转化率;
何为优化
- 一个数据包从手机出发要经过无线网络、核心网络以及外部网络(互联网),才能到达我们的服务器;
(手机 => 无线网络 => 基站 => 运营商核心网 => 互联网 => 服务器)
影响网络请求速度的因素:
- 客户端网络库的内部设计和策略:IO并发模型,针对网络问题的优化
- 服务器性能:并发能力,带宽能力
- 网络相关:用户网络(弱网,强网),运营商,网络链路
网络优化的核心:
- 速度,弱网络,安全,其他的还有造成的耗电,流量问题;
网络请求步骤:
- DNS解析:通过DNS服务器拿到对应域名的IP,需要关注 DNS解析耗时,运营商LocalDns劫持,DNS调度等;
- 创建连接:与服务器建连接,包括TCP三次握手,TLS密钥协商等,需要关注 多个IP/端口如何选择,是否使用HTTPS,能否减少创建连接的时间;
- 发送/接受数据:数据的组装,发送,接收,解析,需要关注 根据网络状况利用带宽,侦测网络延时,弱网下调整包大小;
- 关闭连接:需要关注 主动关闭和被动关闭两种情况;
HTTPDNS
- DNS解析是网络请求的第一步,默认使用运营商的LocalDNS服务;
LocalDNS存在的问题:
- 解析慢,4G约100ms,3G约200~300ms
- 稳定性:UDP协议,无状态,容易域名劫持(难复现,难定位,难解决)
- 准确性:调度经常不准确,跨地域,跨运营商调度会导致访问慢,甚至访问不了
- 及时性:运营商可能修改DNS的TTL,导致DNS修改生效延迟
- 为了解决上述问题就有了HTTPDNS,即自己做域名解析,通过http请求后台去拿到域名对应的IP地址,大网络平台会有统一的HTTPDNS服务,并和运维系统打通,还会增加精准的流量调度,网络拨测/灰度,网络容灾等;
连接复用
- 前面对比网络库中讲的连接管理,网络库不会吧连接立刻释放,而是放到连接池中,如果有另一个请求的域名和端口是一样的,就可以复用,减少建立连接耗时(TCP三次握手,TLS密钥协商等);
- 原理:利用HTTP协议里的keep-alive,或HTTP/2.0的多路复用(多条请求在这条连接上并发进行)
- 问题:常用的OkHttp对应HTTP/2.0的连接,同一个域名只会保留一条连接,网络拥塞的时候容易出现TCP队首拥塞问题,这种情况可以通过修改网络库或者禁用HTTP/2.0解决;
压缩与加密
- 讲完连接,再来看看发送和接收的优化,第一重要的就是减少传输的数据量,也就是数据压缩;
对于HTTP请求数据主要有三部分:
- 请求header:HTTP/2.0本身有头部压缩技术
- 请求URL:一般我们会有很多公共参数,这些参数大部分是不变的,可以只上传一次,在统一接入层进行参数扩展
- 请求body:一是通信协议的选择,在网络传输中目前最流行的两种数据序列化方式是 JSON 和 Protocol Buffers,Protocol Buffers 使用起来更加复杂一些,但在数据压缩率、序列化与反序列化速度上面都有很大的优势。二是压缩算法的选择,通用的压缩算法主要是如 gzip,Google 的Brotli或者 Facebook 的Z-standard都是压缩率更高的算法。
- 针对特定数据我们还有其他的压缩方法,例如针对图片我们可以使用 webp、hevc、SharpP等压缩率更高的格式。另外一方面,基于 AI 的图片超清化也是一大神器,QQ 空间通过这个技术节约了大量的带宽成本。
安全
- 数据安全也是网络重中之重的一个环节,在大网络平台中是基于 HTTPS 的 HTTP/2 通道,已经有了 TLS 加密。
- 但是 HTTPS 带来的代价也是不小的,它需要 2-RTT 的协商成本,在弱网络下时延不可接受。同时后台服务解密的成本也十分高昂,在大型企业中需要单独的集群来做这个事情。
HTTPS 的优化
- 连接复用率:多个域名共用同一个 HTTP/2 连接、长连接等方式
- 减少握手次数:TLS 1.3可以实现 0-RTT 协商,事实上在 TLS 1.3 release 之前,微信的mmtls、Facebook 的fizz、阿里的 SlightSSL 都已在企业内部大规模部署。
- 性能提升:使用 ecc 证书代替 RSA,服务端签名的性能可以提升 4~10 倍,但是客户端校验性能降低了约 20 倍,从 10 微秒级降低到 100 微秒级。另外一方面可以通过 Session Ticket 会话复用,节省一个 RTT 耗时。
- 其他优化:一些方案可能是需要用钱堆出来的,比如部署跨国的专线、加速点,多 IDC 就近接入等。除此之外,使用CDN 服务、P2P 技术也是比较常用的手段,特别在直播这类场景。
- 异地多活:多个地区同时存在对等的多个机房,以用户维度划分,多机房共同承担全量用户的流量。
- 抗抖动优化:应用一种有策略的重试机制,将网络请求以是否发送到 socket 缓冲区作为分割
- SYNC 机制:同步差量数据,达到节省流量,提高通信效率与请求成功率。客户端用户不在线时,SYNC 服务端将差量数据保持在数据库中。当客户端下次连接到服务器时,再同步差量数据给用户。
- 高并发流量处理:服务端接入层多级限流,
- JobScheduler:结合 JobScheduler 来根据实际情况做网络请求. 比方说 Splash 闪屏广告图片, 我们可以在连接到 Wifi 时下载缓存到本地; 新闻类的 App 可以在充电, Wifi 状态下做离线缓存。
- 网络请求优先级排序:app应该对网络请求划分优先级尽可能快地展示最有用的信息给用户。(高优先级的服务优先使用长连接)
- 建立长连通道:将众多请求放入等待发送队列中,待长连通道建立完毕后再将等待队列中的请求放在长连通道上依次送出。
- 减少域名和避免重定向
- 没有请求的请求,才是最快的请求。
移动端监控
- 不论是基站故障、光纤被挖断、运营商挟持,还是我们的机房、CDN 服务商出现故障,都有可能会引起用户网络出现问题。
- 即使我们使用了OkHttp网络库,也可能会有一些开发人员或者第三方组件使用了系统的网络库。那应该如何统一的监控客户端的所有的网络请求呢?
1. 插桩:
- 360 开源的性能监控工具ArgusAPM就是利用 Aspect 切换插桩,实现监控系统和 OkHttp 网络库的请求。(参考其TraceNetTrafficMonitor,OkHttp3Aspect)
- 插桩的方法看起来很好,但是并不全面。如果使用的不是系统和 OkHttp 网络库,又或者使用了 Native 代码的网络请求,都无法监控到。
2. Native Hook:
- 参考https://github.com/AndroidAdvanceWithGeektime/Chapter17
- 这种做法不好的地方在于会把系统的 Local Socket 也同时接管了,需要在代码中增加过滤条件。
3. 统一网络库
- 尽管拿到了所有的网络调用,想想会有哪些使用场景呢?模拟网络数据、统计应用流量,或者是单独代理 WebView 的网络请求。
如何监控流量
- 应用流量监控的方法非常简单,一般通过 TrafficStats 类。TrafficState 是 Android API 8 加入的接口,用于获取整个手机或者某个 UID 从开机算起的网络流量。至于如何使用可以参考https://github.com/facebook/network-connection-class;
getMobileRxBytes() //从开机开始Mobile网络接收的字节总数,不包括Wifi
getTotalRxBytes() //从开机开始所有网络接收的字节总数,包括Wifi
getMobileTxBytes() //从开机开始Mobile网络发送的字节总数,不包括Wifi
getTotalTxBytes() //从开机开始所有网络发送的字节总数,包括Wifi
//原理:读取 proc,并将目标 UID 下面所有网络接口的流量相加。
//Android 7.0 之后只能通过 TrafficStats 拿到自己应用的流量信息
网络测试模式:
- Android 手机跟 iPhone 都有一个网络测试模式
- iPhone:打开拨号界面,输入“3001#12345#”,然后按拨号键。
- Android 手机:打开拨号界面,输入“##4636##”,然后按拨号键(可进入工程测试模式,部分版本可能不支持)。
参考
我是今阳,如果想要进阶和了解更多的干货,欢迎关注微信公众号 “今阳说” 接收我的最新文章
|