IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Okhttp链接池的使用,看完这一篇你就懂了 -> 正文阅读

[网络协议]Okhttp链接池的使用,看完这一篇你就懂了

 并向connection持有的allocations中增加了一条新的流的弱引用
也就是往这条连接中增加了一条流。 
```

而其中的条件为isEligible,跟踪进去可以看到,具体的条件为

1.  当前这次连接的最大并发数没有达到上限
2.  两个address的其他参数相同
3.  两个address的url的host相同

若满足以上条件,则说明host是相同的可以直接复用,如果不满足以上条件的话,仍旧有机会使用连接(将连接合并):

1.  首先这个连接需要使用HTTP/2
2.  要与复用前的Ip address相同,且不能使用代理
3.  这个连接的服务器证书授权中,必须包括新的主机。
4.  锁定证书(certificatePinner)必须匹配主机

```
public boolean isEligible(Address address, @Nullable Route route) {
  // If this connection is not accepting new streams, we're done.
  if (allocations.size() >= allocationLimit || noNewStreams) return false;

  // If the non-host fields of the address don't overlap, we're done.
  if (!Internal.instance.equalsNonHost(this.route.address(), address)) return false;

  // If the host exactly matches, we're done: this connection can carry the address.
  if (address.url().host().equals(this.route().address().url().host())) {
    return true; // This connection is a perfect match.
  }

  // At this point we don't have a hostname match. But we still be able to carry the request if
  // our connection coalescing requirements are met. See also:
  // https://hpbn.co/optimizing-application-delivery/#eliminate-domain-sharding
  // https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/

  // 1. This connection must be HTTP/2.
  if (http2Connection == null) return false;

  // 2. The routes must share an IP address. This requires us to have a DNS address for both
  // hosts, which only happens after route planning. We can't coalesce connections that use a
  // proxy, since proxies don't tell us the origin server's IP address.
  if (route == null) return false;
  if (route.proxy().type() != Proxy.Type.DIRECT) return false;
  if (this.route.proxy().type() != Proxy.Type.DIRECT) return false;
  if (!this.route.socketAddress().equals(route.socketAddress())) return false;

  // 3. This connection's server certificate's must cover the new host.
  if (route.address().hostnameVerifier() != OkHostnameVerifier.INSTANCE) return false;
  if (!supportsUrl(address.url())) return false;

  // 4. Certificate pinning must match the host.
  try {
    address.certificatePinner().check(address.url().host(), handshake().peerCertificates());
  } catch (SSLPeerUnverifiedException e) {
    return false;
  }

  return true; // The caller's address can be carried by this connection.
} 
```
  1. 连接池的清理和回收

    在put方法中已经用过了连接池的清理和回收 executor.execute(cleanupRunnable);现在变来详细看下其所做的事情:跟踪进入cleanupRunnable,发现其逻辑为定时执行cleanup,其中的定时等待是加入了同步锁,不允许打断。

    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) {
              }
            }
          }
        }
      }
    }; 
    

    下面聚焦的重点clean up之中。总的来说他的作用是找到限制的链接并清理,具体分析可以发现:

    • 其通过inUseConnectionCount记录正在使用的链接数目,利用idleConnectionCount记录闲置的链接数。这两个链接数目的改变,都是通过pruneAndGetAllocationCount()方法控制的,起作用也就自然而然为判断传入的链接是闲置的还是运行的。
    • 程序又根据闲置时间对connection 选择了一个限制时间最长的链接,如果其大于keep_alive的极限时间(keepAliveDurationNs 5分钟),或者空闲链接个数大于连接池的最大值(maxIdleConnections5个),则移除该connection
    long cleanup(long now) {
      int inUseConnectionCount = 0;
      int idleConnectionCount = 0;
      RealConnection longestIdleConnection = null;
      long longestIdleDurationNs = Long.MIN_VALUE;
    
      // Find either a connection to evict, or the time that the next eviction is due.
      synchronized (this) {
        for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
          RealConnection connection = i.next();
    
          // If the connection is in use, keep searching.
          if (pruneAndGetAllocationCount(connection, now) > 0) {
            inUseConnectionCount++;
            continue;
          }
    
          idleConnectionCount++;
    
          // If the connection is ready to be evicted, we're done.
          long idleDurationNs = now - connection.idleAtNanos;
          if (idleDurationNs > longestIdleDurationNs) {
            longestIdleDurationNs = idleDurationNs;
            longestIdleConnection = connection;
          }
        }
    
        if (longestIdleDurationNs >= this.keepAliveDurationNs
            || idleConnectionCount > this.maxIdleConnections) {
          // We've found a connection to evict. Remove it from the list, then close it below (outside
          // of the synchronized block).
          connections.remove(longestIdleConnection);
        } else if (idleConnectionCount > 0) {
          // A connection will be ready to evict soon.
          return keepAliveDurationNs - longestIdleDurationNs;
        } else if (inUseConnectionCount > 0) {
          // All connections are in use. It'll be at least the keep alive duration 'til we run again.
          return keepAliveDurationNs;
        } else {
          // No connections, idle or in use.
          cleanupRunning = false;
          return -1;
        }
      }
    
      closeQuietly(longestIdleConnection.socket());
    
      // Cleanup again immediately.
      return 0;
    } 
    

    跟踪进去,发现其是通过维护Reference类型的链表(references)达到效果的。起作用为记录connection 活跃情况的(>0 表示活跃=0 表示空闲)

    整体逻辑的核心为:如果 StreamAlloction 引用空闲,但是connection的引用列表中仍旧存在该项,那么便发生了内存泄露

    //用于清理可能泄露的 StreamAllocation并返回正在使用此连接的StreamA1location的数量,
    private int pruneAndGetAllocationCount(RealConnection connection, long now) {
      List<Reference<StreamAllocation>> references = connection.allocations;
      for (int i = 0; i < references.size(); ) {
        Reference<StreamAllocation> reference = references.get(i);
    
        if (reference.get() != null) {
          i++;
          continue;
        } //表示该流活跃
    
        // We've discovered a leaked allocation. This is an application bug.
        StreamAllocation.StreamAllocationReference streamAllocRef =
            (StreamAllocation.StreamAllocationReference) reference;
        String message = "A connection to " + connection.route().address().url()
            + " was leaked. Did you forget to close a response body?";
        Platform.get().logCloseableLeak(message, streamAllocRef.callStackTrace);
    
        references.remove(i);
        connection.noNewStreams = true;
    
        // If this was the last allocation, the connection is eligible for immediate eviction.
        if (references.isEmpty()) {
    
    
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-09-04 17:54:21  更:2021-09-04 17:54:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年6日历 -2024/6/27 1:40:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码