美文网首页
Android 网络知识梳理

Android 网络知识梳理

作者: FelixLiuu | 来源:发表于2019-08-07 10:58 被阅读0次

1、网络体系结构

TCP/IP 体系结构 五层体系结构
5.应用层
4.应用层(HTTP) 4.运输层
3.运输层(TCP、UDP) 3.网络层
2.网际层(IP) 2.链路层
1.网络接口层 1.物理层

其中 我们熟悉的 HTTP DNS POP FTP SSH 等协议,都存在于 应用层

TCP

特点

面向连接、面向字节流、全双工通信、可靠

优缺点

优点:数据传输可靠
缺点:效率慢(因需建立连接、发送确认包等)

建立连接

TCP的三次握手

第一次握手:客户端向服务器发送一个连接请求的报文段
第二次握手:服务器收到请求连接报文段后,若同意建立连接,则向客户端发回连接确认的报文段
第三次握手:大客户收到确认报文段后,向服务器再次发出连接确认报文段
注:三次握手期间,任何一次未收到对面的回复,则都会重发

成功进行TCP的三次握手后,就建立起一条TCP连接,即可传送应用层数据

为什么TCP建立要三次握手

结论:防止服务器端因接收了早已失效的连接请求报文,从而一直等待客户端请求,最终导致形成死锁、浪费资源

释放连接

TCP的四次握手

第一次握手:客户端向服务器发送一个连接释放的报文段
第二次握手:服务器收到连接释放报文段后,则向客户端发回连接释放确认的报文段(至此,TCP连接处半关闭状态,即 客户端->服务器TCP已断开, 服务器-> 客户端未断开
第三次握手:若服务器已无要向客户端发送数据,则发出释放连接的报文段(服务器进入最后确认状态
第四次握手:客户端收到连接释放报文段后,向服务器发回连接释放确认的报文段(经过2MSL后,客户端进入关闭状态,服务器比客户端先关闭
注:MSL=最长报文段寿命(Maximum Segment Lifetime)

为什么TCP释放要四次握手

结论:为了保证通信双方都能通知对方 需释放 & 断开连接

HTTP

是基于TCP的应用层协议

请求

请求行 、请求头(header)、请求体(可选,GET 可无请求数据

响应

响应行 、响应头(header)、响应体

GET POST 区别

使用方式 传参长度限制 传参类型 安全性 应用场景
GET 最长2048个字符http1.1后无限制 只允许ASCII 字符 小量、数据不敏感
POST 不受限制 任何类型 大量、数据敏感

HTTP1.1 与 HTTP1.0的区别

  1. 缓存处理:HTTP/1.0 使用 Pragma:no-cache + Last-Modified/If-Modified-Since来作为缓存判断的标准;HTTP/1.1 引入了更多的缓存控制策略:Cache-Control、Etag/If-None-Match等。

  2. 错误状态管理:HTTP/1.1新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

  3. 范围请求:HTTP/1.1在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接,支持断点续传。

  4. Host头:HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。有了Host字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。

  5. 持久连接:HTTP/1.1 最大的变化就是引入了持久连接(persistent connection),在HTTP/1.1中默认开启 Connection: keep-alive,即TCP连接默认不关闭,可以被多个请求复用。

  6. 管道机制:HTTP/1.1中引入了管道机制(pipelining),即在同一个TCP连接中,客户端可以同时发送多个请求。

HTTP1.1 与 HTTP2.0的区别

Http2.0是以Google发布的SPDY协议为基础的。HTTP/2协议只在HTTPS环境下才有效,升级到HTTP/2,必须先启用HTTPS。HTTP/2解决了HTTP/1.1的性能问题,主要如下:

  1. 二进制分帧:HTTP/1.1的头信息是文本(ASCII编码),数据体可以是文本,也可以是二进制;HTTP/2 头信息和数据体都是二进制,统称为“帧”:头信息帧和数据帧;

  2. 多路复用(双工通信):通过单一的 HTTP/2 连接发起多重的请求-响应消息,即在一个连接里,客户端和浏览器都可以同时发送多个请求和响应,而不用按照顺序一一对应,这样避免了“队头堵塞”。HTTP/2 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息。并行地在同一个 TCP 连接上双向交换消息。

  3. 数据流:因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。HTTP/1.1取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。

  4. 头部压缩:HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息压缩后再发送(SPDY 使用的是通用的DEFLATE 算法,而 HTTP/2 则使用了专门为首部压缩而设计的 HPACK 算法)。;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。

  5. 服务端推送:HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。

HTTP 与 HTTPS的区别

类型 原理 功能 性能 标准端口 CA申请证书
HTTP 应用层 不加密 不安全 80 不要
HTTPS 传输层 加密SSL加密 身份认证 安全 443 需要

HTTPS加密原理

HTTPS = HTTP + SSL/TLS(安全套接层Secure Sockets Layer/安全传输层Transport Layer Security)。也就是在传统的HTTP和TCP之间加了一层用于加密解密的SSL/TLS层。
一篇读懂HTTPS

Socket

套接字,是应用层 与 TCP/IP 协议通信的中间软件抽象层,表现为一个封装了TCP/IP协议的编程接口

  • Socket不是一种协议,而是一个编程调用接口(API),属于传输层(主要解决数据如何在网络中传输)
  • 通过Socket,我们才能在Andorid平台上通过 TCP/IP协议进行开发
  • 对用户来说,只需调用Socket去组织数据,以符合指定的协议,即可通信

2、Retrofit 2

Retrofit 本质上是一个 RESTful 的 HTTP 网络请求框架的封装,即通过 大量的设计模式 封装了 OkHttp ,使得简洁易用。具体过程如下:

  1. Retrofit 将 Http请求 抽象 成 Java接口
  2. 在接口里用 注解 描述和配置 网络请求参数
  3. 用动态代理 的方式,动态将网络请求接口的注解 解析 成HTTP请求
  4. 最后执行HTTP请求

一张 大神 的源码分析图:

源码分析图

3、OKHttp 3

  1. 支持 HTTP1.1/HTTP2 和 SPDY
  2. 对同一主机共享同一个socket连接,减少握手次数,提高效率
  3. 支持Gzip 降低传输内容大小
  4. 支持自动重连
  5. 拥有Dispatcher线程池,并发支持
  6. 拥有Interceptor拦截器及调用链,轻松处理请求和响应

OkHttp系统图

系统图

OkHttp 创建了 实例对象 OkHttpClient ,支持 WebSocket(RealWebSocket)Call(RealCall) 。常使用的 Call 方法,内部是 Dispatcher 线程池 ,实际是 线程池 支持 execute (同步)enqueue(异步) 调用。同步 异步 都使用了 RealInterceptorChain 链式调用方式。最后通过 StreamAllocationRealConnectionHttpCodec 发送网络请求并得到结果

OkHttpClient

OkHttpClient 是 OkHttp 通过 建造者模式 创建的实例对象。

public class OkHttpClient implements Cloneable, Call.Factory,     WebSocket.Factory {
  static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(
  Protocol.HTTP_2, Protocol.HTTP_1_1);

  static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
  ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);

    ......
}

可见,默认支持 http2http1.1,默认使用 TSL 安全协议。

WebSocket

WebSocket 是一种在TCP协议上进行的 全双工通信的协议,支持服务器想客户端的发送请求。

@Override public WebSocket newWebSocket(Request request, WebSocketListener listener) {
RealWebSocket webSocket = new RealWebSocket(request, listener, new Random(), pingInterval);
webSocket.connect(this);
return webSocket;

}

Call(RealCall)

@Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

Call 的实际操作对象是 RealCall

final class RealCall implements Call {
  ......

  static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
  }
}

RealCall 是真正触发网络请求的类(实现Call接口,一次请求 = 一个RealCall实例),它提供了同步请求、异步请求

execute 同步请求

@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
     executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }
  1. client.dispatcher().executed(this) 同步调用主要是使用了 dispatcher 线程池的同步方法
  2. getResponseWithInterceptorChain () 采用了 链式方式 获取响应

enqueue 异步请求

 @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

client.dispatcher().enqueue(new AsyncCall(responseCallback)); 创建了 AsyncCall 交给 dispatcher线程池 异步处理

    final class AsyncCall extends NamedRunnable {
      // ......
    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

Dispatcher线程池

Dispatcher 管理网络请求的线程池,就是把同步 RealCall 与异步 RealCall .AsyncCall 的请求放进集合中统一管理。

  • RealCall 在Dispatcher中,其实主要就是一个存储功能(即用一个集合把RealCall的请求进行存储)。
  • AsyncCall 在Dispatcher中,除了使用集合存储AsyncCall的请求,Dispatcher还初始化了一个线程池(ThreadPoolExecutor)处理AsyncCall的网络请求。
public final class Dispatcher {
  private int maxRequests = 64; //最大请求数量
  private int maxRequestsPerHost = 5; //相同host的最大请求数据
  private @Nullable Runnable idleCallback;

  ......

  //同步请求
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

  // 异步请求
  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }
}

Interceptor拦截器及调用链

同、异步请求中都调用了 getResponseWithInterceptorChain() 方法。

    Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
    }
  1. client.interceptors()
    • 添加OkHttp 自定义的 拦截器。如 HttpLoggingInterceptor
  2. RetryAndFollowUpInterceptor
    • 定义:重定向拦截器;
    • 作用:在无法请求服务器或者请求失败时,服务器会告诉客户端可以处理请求的url,然后重定向拦截器承当重新请求新url的作用(服务器返回3XX错误码为重定向,可以通过响应头的Location获取新请求的url);
  3. BridgeInterceptor
    • 定义:桥拦截器;
    • 作用:封装请求头(Content-Type、Connection、Cookie...)与响应头("Content-Encoding...)的信息。
  4. CacheInterceptor
    • 定义:缓存拦截器;
    • 作用:为网络请求提供缓存功能,加快相同请求的访问速度,减少资源损耗。
  5. ConnectInterceptor
    • 定义:连接拦截器;
    • 作用:与服务器建立通讯连接。
  6. CallServerInterceptor
    • 定义:请求服务器拦截器;
    • 作用:与服务器进行数据通讯(包含请求头、请求内容)。

注:调用链采用 *责任链* 的方式,向下请求,向上响应。类似 Android View 的事件传递

StreamAllocation、RealConnection、HttpCodec 连接与请求

  1. StreamAllocation :负责初始化 RealConnection、HttpCodec,并将前2者与RealCall进行关联;
  • StreamAllocation 在 RetryAndFollowUpInterceptor 中初始化
  • RealConnection 在 ConnectInterceptor 中通过 StreamAllocation 的 newStream() 初始化
  • HttpCodec 在 RealConnection 中被初始化
  1. RealConnection:真正负责完成网络连接
connectSocket(connectTimeout, readTimeout, call, eventListener); 

最后通过 Socket 进行网络连接

  1. HttpCodec:负责完成发送请求头与数据内容(使用okio完成数据的写入与读出)

Http1CodecHttp2Codec,分包处理 HTTP1.1 和 HTTP2.0 的数据传递

相关文章

网友评论

      本文标题:Android 网络知识梳理

      本文链接:https://www.haomeiwen.com/subject/rafclctx.html