privateRealConnectionfindConnection(int connectTimeout,int readTimeout,int writeTimeout,boolean connectionRetryEnabled)throwsIOException{Route selectedRoute;synchronized(connectionPool){...// 注释1:从链接池中遍历,找到合适的链接Internal.instance.get(connectionPool, address,this,null);if(connection !=null){return connection;}}...// 注释2:链接池中没有可以用的链接,则创建一个链接
result =newRealConnection(connectionPool, selectedRoute);...// 注释3:建立链接,通过socket
result.connect(connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled);routeDatabase().connected(result.route());Socket socket =null;synchronized(connectionPool){// 注释4:添加到链接池中,并且会开启一个线程池任务监听每个链接的空闲状态,是否需要被清理Internal.instance.put(connectionPool, result);if(result.isMultiplexed()){
socket =Internal.instance.deduplicate(connectionPool, address,this);
result = connection;}}closeQuietly(socket);return result;}// 从链接池中找一个可用的链接@NullableRealConnectionget(Address address,StreamAllocation streamAllocation,Route route){assert(Thread.holdsLock(this));for(RealConnection connection : connections){// 匹配域名和端口一致的链接if(connection.isEligible(address, route)){
streamAllocation.acquire(connection);return connection;}}returnnull;}publicbooleanisEligible(Address address,@NullableRoute route){// 校验当前是否允许再创建链接流if(allocations.size()>= allocationLimit || noNewStreams)returnfalse;// 域名跟端口一致的链接,即为可用if(!Internal.instance.equalsNonHost(this.route.address(), address))returnfalse;if(address.url().host().equals(this.route().address().url().host())){returntrue;// 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)returnfalse;// 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)returnfalse;if(route.proxy().type()!=Proxy.Type.DIRECT)returnfalse;if(this.route.proxy().type()!=Proxy.Type.DIRECT)returnfalse;if(!this.route.socketAddress().equals(route.socketAddress()))returnfalse;// 3. This connection's server certificate's must cover the new host.if(route.address().hostnameVerifier()!=OkHostnameVerifier.INSTANCE)returnfalse;if(!supportsUrl(address.url()))returnfalse;// 4. Certificate pinning must match the host.try{
address.certificatePinner().check(address.url().host(),handshake().peerCertificates());}catch(SSLPeerUnverifiedException e){returnfalse;}returntrue;// The caller's address can be carried by this connection.}