OkHttp源码解析(三)

本篇将解析ConnectionPool连接池类,此类的主要目的是解决TCP3次握手与4次挥手的效率问题。

tcp的3次握手与4次挥手又有什么样的问题,如何去解决呢?

导致问题3次握手与4次挥手的效率问题:如果有大量的链接,每次链接与关闭时都要经历3次握手与4次挥手,那么很显然会造成性能低下的问题。

解决方案:HTTP中有一种keepalive connection的机制,它可以在传输数据后任保持链接,当客户端需要再次获取数据时,直接使用刚刚空闲下来的链接而无需再次握手。

(一)ConnectionPool类

public final class ConnectionPool {
 

//类似与缓存型的线程池
  private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */,
      Integer.
MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
     
new SynchronousQueue<Runnable>(), Util.threadFactory(“OkHttp ConnectionPool”, true));

 
/** The maximum number of idle connections for each address. */
 
private final int maxIdleConnections; //空闲socket的最大连接数
  private final long keepAliveDurationNs; //socketkeepAlive时间
  private final Runnable cleanupRunnable = new Runnable() {
   
@Override public void run() {
     
while (true) {
       
long waitNanos = cleanup(System.nanoTime());
       
if (waitNanos == -1) return;
       
if (waitNanos > 0) {
         
long waitMillis = waitNanos / 1000000L;
          waitNanos -= (waitMillis *
1000000L);
         
synchronized (ConnectionPool.this) {
           
try {
              ConnectionPool.
this.wait(waitMillis, (int) waitNanos);
            }
catch (InterruptedException ignored) {
            }
          }
        }
      }
    }
  };

// Deque双向队列,双端队列同时具有队列和栈的性质,经常在缓存中被使用  --》核心
  private final Deque<RealConnection> connections = new ArrayDeque<>();
 
final RouteDatabase routeDatabase = new RouteDatabase();
 
boolean cleanupRunning;

 
/**
   * Create a new connection pool with tuning parameters appropriate for a single-user application.
   * The tuning parameters in this pool are subject to change in future OkHttp releases. Currently
   * this pool holds up to 5 idle connections which will be evicted after 5 minutes of inactivity.
   */
 
public ConnectionPool() {
   
this(5, 5, TimeUnit.MINUTES); //默认的空闲socket最大连接数为5socketkeepAlive时间的5分钟
  }

 
public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
   
this.maxIdleConnections = maxIdleConnections;
   
this.keepAliveDurationNs = timeUnit.toNanos(keepAliveDuration);

   
// Put a floor on the keep alive duration, otherwise cleanup will spin loop.
   
if (keepAliveDuration <= 0) {
     
throw new IllegalArgumentException("keepAliveDuration <= 0: " + keepAliveDuration);
    }
  }

 ………..
  /**
   * Returns a recycled connection to {
@code address}, or null if no such connection exists. The
   * route is null if the address has not yet been routed.
   */

  //获取链接
  @Nullable RealConnection get(Address address, StreamAllocation streamAllocation, Route route) {
   
assert (Thread.holdsLock(this));
   
for (RealConnection connection : connections) {
     
if (connection.isEligible(address, route)) {
        streamAllocation.acquire(connection);
       
return connection;
      }
    }
   
return null;
  }


   @Nullable Socket deduplicate(Address address, StreamAllocation streamAllocation) {….  }

//放入链接
  void put(RealConnection connection) {
   
assert (Thread.holdsLock(this));
   
if (!cleanupRunning) {
     
cleanupRunning = true;
     
executor.execute(cleanupRunnable);
    }
   
connections.add(connection);
  }

 
/**
   * Notify this pool that {
@code connection} has become idle. Returns true if the connection has
   * been removed from the pool and should be closed.
   */

  //移除链接
  boolean connectionBecameIdle(RealConnection connection) {……….}

 
/** Close and remove all idle connections in the pool. */

   //移除所有的链接操作
  public void evictAll() { ………….  }

  ………….
}

 

(二)okhttp缓存流程

Interceptor 的布局,在建立连接、和服务器通讯之前,就是 CacheInterceptor,在建立连接之前,我们检查响应是否已经被缓存、缓存是否可用,如果是则直接返回缓存的数据,否则就进行后面的流程,并在返回之前,把网络的数据写入缓存。

 

(三)OkHttp流程图(借鉴@piasy的图)

猜你喜欢

转载自blog.csdn.net/qq_33429583/article/details/81771599