HTTPS

流程图

未命名文件 (34).jpg

流程

  • HTTPS = http + ssl/tls

image.png

TCP VS UDP

  • https://www.cnblogs.com/liangyc/p/11628208.html
  • 区别

    • 面向链接VS无链接
      • TCP建立一个连接需要3次握手IP数据包,断开连接需要4次握手。另外断开连接时发起方可能进入TIME_WAIT状态长达数分钟(视系统设置,windows一般为120s),在此状态下连接(端口)无法被释放
      • UDP不需要建立连接,可以直接发送
    • 可靠VS不可靠
      • TCP利用握手、ACK和重传机制保证可靠性,UDP则没有
        • 校验和、确认应答与序列号、超时重传、连接管理、浏览控制、阻塞控制
    • 有序性
      • TCP利用seq序列号对包进行排序,udp没有
    • 面向字节流VS面向报文
      • 面向报文
        • 面向报文的传输方式是应用层交给UDP多长的报文,DUP就照样发送,即一次发送一个报文。因此,应用程序必须选择比较合适大小的报文。若报文太长,则IP层需要分片。UDP对应用层交下来的报文,既不合并、也不拆分,而是保留这些报文的边界。(一个UDP的最大报文长度2^16-1-20-8,20是ip报文头,8是udp报文头)
      • 面向字节流
        • 面向字节流的话,虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序看成是一连串的无结构的字节流。TCP有一个缓冲,当应用程序传输的数据块太长,TCP就可以把它划分短一些再传送。如果应用程序一次只发送一个字节,TCP也可以等待积累有足够多的字节后再构建成报文段发送出去。
    • TCP有浏览控制,UDP没有
    • TCP头部20~60字节,UDP8字节
    • 应用场景
      • TCP,文件传输、接受邮寄、远程登录
      • UDP,QQ聊天、在线视频、网络语音通话、广播通信

        TCP

  • TCP -> 传输控制协议,这是传输层的一个协议,对数据的传输进行详细的控制。

    • 面向字节流
    • 安全可靠
    • 面向连接
  • TCP可靠性
    • 校验和
    • 确认应答与序列号
    • 超时重传
    • 链接管理
    • 流量控制
    • 阻塞控制

未命名文件 (36).jpg

  • 三次握手、四次挥手※

  • 特点

    • 无连接
    • 不可靠
    • 面向数据包
    • 速度快

image.png

HTTP报文格式

音视频设备模块框架图 (9).jpg

状态码

  • 200 -> 成功
  • 301 -> 重定向, 302 -> 永久重定向
  • 4开头,代表客户端问题,404 -> 资源找不到
  • 5开头,代表服务端问题

    http1.0、2.0区别

  • http://io.upyun.com/2015/05/13/http2/

  • http2采用二进制格式而不是文本格式
  • http2多路复用格式,而非有序并阻塞,只有一个链接即可
  • 使用报头压缩,降低了开销
  • http2让服务端可以将响应主动推送到客户端

    用户态 VS 内核态

  • 内核态 -> 控制计算机的资源,如协调CPU资源,分配内存资源,并且提供稳定的运行环境供应用程序运行。

  • 用户态 -> 提供应用程序运行的空间,为了使应用程序能访问到的内核管理的资源例如CPU、内存、I/O。内核必须提供一系列通用的访问接口,这些接口就叫操作系统。

音视频设备模块框架图 (10).jpg

  • 用户态到内核态切换的三种方式:
    • 系统调用 -> 其实系统调用本身就是中断,但是软件中断,跟硬中断不同。
    • 异常 -> 如果当前进程运行在用户态,如果这个时候发生了异常事件,就会触发切换。例如:缺页异常。
    • 外设中断 -> 当外设完成用户的请求时,会向CPU发送中断信号。
  • 中断具体操作步骤

① 从当前进程的描述符中提取其内核栈的ss0及esp0信息。
②使用ss0和esp0指向的内核栈将当前进程的cs,eip,eflags,ss,esp信息保存起来,这个过程也完成了由用户栈到内核栈的切换过程,同时保存了被暂停执行的程序的下一条指令。
③ 将先前由中断向量检索得到的中断处理程序的cs,eip信息装入相应的寄存器,开始执行中断处理程序,这时就转到了内核态的程序执行了。

Socket

  • Socket就是插座,端口就是插座上的孔, 端口不能被其他进程占用;
  • 抽象理解Socket类似于操作某个IP地址上的某个端口达到点对点通信的目的,
  • 绑定到某个具体的进程中和端口中;
  • 服务端:

    • 建议服务端的socket服务.ServerSocket()并监听一个端口
    • 获取连接过来的客户端对象
      • 通过ServerSocket的accept方法,返回值是Socket
      • 没有链接就会等,所以这个方法时阻塞式的
    • 客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据,并打印在控制台
    • 关闭服务端(可选)

      Protobuf

  • protobuf序列化为二进制和json序列化字符串大小

    • pb:58字节
    • json:110字节,删掉空格还有100字节
  • 更容容易绑定值到对象的字段上。JSON 的字段是用字符串指定的,相比之下字符串比对应该比基于数字的字段tag更耗时。
  • JSON 是文本的格式,整数和浮点数应该更占空间而且更费时。
  • Protobuf 在正文前有一个大小或者长度的标记,而 JSON 必须全文扫描无法跳过不需要的字段。

    Unicode与UTF-8区别

  • https://www.zhihu.com/question/23374078

    进程IPC通信

  • 消息传递(管道、FIFO、消息队列)

  • 同步(互斥量、条件变量、读写锁、信号量)
  • 共享内存(匿名和具名的)
  • 远程过程调用(Solaris、Sun RPC)

    HPACK算法

  • HTTP2相对HTTP1进行了头部压缩,主要由两张表组成,静态表和动态表


移动端网络优化

一、分析网络请求流程及耗时

(1)网络请求过程

  • 发起请求->域名解析->tcp三次握手->tls握手->request->response->json解析->业务

    (2)耗时统计

  • 在了解了网络请求的流程之后,我们可以先测试以下自己项目网络请求耗时分布,对iOS来说。

  • 获取耗时最简单的方式就是监听NSURLSession的didFinishCollectingMetrics回调方法 ```objectivec
    • (void)URLSession:(NSURLSession )session task:(NSURLSessionTask )task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0))

{ if (@available(iOS 10.0, )) { for (NSURLSessionTaskTransactionMetrics sessionMetric in metrics.transactionMetrics) { NSInteger dom = ([sessionMetric.domainLookupEndDate timeIntervalSince1970] - [sessionMetric.domainLookupStartDate timeIntervalSince1970]) 1000 ; NSInteger sec = ([sessionMetric.secureConnectionEndDate timeIntervalSince1970] - [sessionMetric.secureConnectionStartDate timeIntervalSince1970]) 1000; NSInteger con = ([sessionMetric.connectEndDate timeIntervalSince1970] - [sessionMetric.connectStartDate timeIntervalSince1970]) 1000; NSInteger req = ([sessionMetric.requestEndDate timeIntervalSince1970] - [sessionMetric.requestStartDate timeIntervalSince1970]) 1000; NSInteger res = ([sessionMetric.responseEndDate timeIntervalSince1970] - [sessionMetric.responseStartDate timeIntervalSince1970]) 1000; NSInteger tot = ([sessionMetric.responseEndDate timeIntervalSince1970] - [sessionMetric.fetchStartDate timeIntervalSince1970]) 1000;

  1. NSString *locip = @"";
  2. NSString *remip = @"";
  3. if (@available(iOS 13.0, *)) {
  4. locip = [NSString stringWithFormat:@"%@", sessionMetric.localAddress];
  5. remip = [NSString stringWithFormat:@"%@", sessionMetric.remoteAddress];
  6. }
  7. NSLog(@"metric path:%@ 总耗时:%ldms, 域名解析:%ldms, 连接耗时:%ldms(包括TLS:%ldms), 请求:%ldms, 回调:%ldms l:%@ r:%@",sessionMetric.request.URL.lastPathComponent,tot,dom,con,sec,req,res, locip, remip);
  8. }
  9. }

} ```

二、优化思路

(1)域名解析耗时

  • 我们常用的HTTP请求,底层基于TCP连接,需要有IP和端口信息。由于IP是可变的,且不好记忆,所以有了域名这样一个字符串帮助人们进行记忆。

  • 字符串到IP需要经过DNS服务器来进行获取,这一过程使用的UDP方式,这一过程的快慢取决于网络质量以及域名映射关系存放的DNS服务器跟你所在地跨级的层级。甚至有一些不可控的情况会导致域名解析出来一个错误的IP地址。

  • 为了提高域名解析速度,以及减低域名污染风险,我们可以使用HTTPDNS的方式来进行IP获取。也可以设计一套IP直连方式获取域名IP池机制。

  • 在APP启动后检查更新DNS服务IP的更新,域名IP池的更新,以及对IP池中的IP进行测速,选择网速较好的IP。在使用IP直连请求时,需要修改request的host,以及证书校验的host。

    (2)链接耗时

  • 建立连接需要的耗时较长,如果能够利用长连接可以保持的特性,那么这块的耗时优化非常可观。

  • 优化这块需要后端支持,我们可以设计一个通道API,将多个域名的请求放在同一个连接中进行请求,这块需要网络库层和后端进行协议开发,业务端可以普遍享受到增益。

  • 当然,我们也要考虑在通道不可用时,及时采用常规请求方式的策略。以及HTTP1.1存在对头阻塞问题,需要在HTTP2.0上才能真正起到优化效果。

  • request及response(download)优化

    • request耗时一般是在服务端,如果遇到耗时较长的情况需要找一下服务端同学排查一下是否有耗时逻辑。response耗时较长一般是网速慢或者数据体积大导致的,体积大这个问题可以通过删除冗余数据,开启gzip,数据分页等方式进行优化。

      (3)json解析

  • json解析在数据量不大的情况下一般耗时不会太多,如果遇到数据量特别大的情况可能就需要考虑怎么降低数据量,采用解析效率更高的库,可以参考如下网图。

  • YYModel原理和MJExtension类似,都是基于runtime进行动态获取属性进行赋值。前者使用了CoreFoundation更底层的方法以及内联函数的应用所以效率上得到了大幅提高。

image.png

(4)业务侧优化

  • 网络请求优先级排布,通过对业务代码梳理,在启动阶段进行高优先级接口请求,对可以合并的接口进行合并,落地点销毁的请求及时取消请求。
  • 升级HTTP2.0,利用其二进制分帧,头部压缩,head block优化的特性,降低请求数据量,提高并发请求效率

    (5)弱网优化

  • 弱网环境是移动APP经常需要面对的问题,地铁、人员密集区域、运动,都有可能导致网络请求不稳定、失败等问题。HTTP1.1、2.0都是采用的TCP连接方式,而TCP需要三次握手,断开后需要重新握手,这些会导致在弱网、运动环境持续请求失败。QUIC协议是谷歌提出的基于UDP的数据传输协议,HTTP3.0就是采用的QUIC实现机制。使用HTTP3.0进行网络请求可以享受到如下这些进步,当然这得服务端和客户端共同配合才能完成。

    • 更好的链接建立方式
    • 更好的拥塞控制
    • 没有对头阻塞的多路复用
    • 向前纠错
    • 连接迁移