httpclient connect连接请求方法源码解读
作者:codecraft
序
本文主要研究一下httpclient的connect
HttpClientConnectionOperator
org/apache/http/conn/HttpClientConnectionOperator.java
public interface HttpClientConnectionOperator { void connect( ManagedHttpClientConnection conn, HttpHost host, InetSocketAddress localAddress, int connectTimeout, SocketConfig socketConfig, HttpContext context) throws IOException; void upgrade( ManagedHttpClientConnection conn, HttpHost host, HttpContext context) throws IOException; }
HttpClientConnectionOperator定义了connect及upgrade方法,它有一个默认的实现类为DefaultHttpClientConnectionOperator
DefaultHttpClientConnectionOperator
org/apache/http/impl/conn/DefaultHttpClientConnectionOperator.java
public class DefaultHttpClientConnectionOperator implements HttpClientConnectionOperator { static final String SOCKET_FACTORY_REGISTRY = "http.socket-factory-registry"; private final Log log = LogFactory.getLog(getClass()); private final Lookup<ConnectionSocketFactory> socketFactoryRegistry; private final SchemePortResolver schemePortResolver; private final DnsResolver dnsResolver; public DefaultHttpClientConnectionOperator( final Lookup<ConnectionSocketFactory> socketFactoryRegistry, final SchemePortResolver schemePortResolver, final DnsResolver dnsResolver) { super(); Args.notNull(socketFactoryRegistry, "Socket factory registry"); this.socketFactoryRegistry = socketFactoryRegistry; this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE; this.dnsResolver = dnsResolver != null ? dnsResolver : SystemDefaultDnsResolver.INSTANCE; } //...... public void connect( final ManagedHttpClientConnection conn, final HttpHost host, final InetSocketAddress localAddress, final int connectTimeout, final SocketConfig socketConfig, final HttpContext context) throws IOException { final Lookup<ConnectionSocketFactory> registry = getSocketFactoryRegistry(context); final ConnectionSocketFactory sf = registry.lookup(host.getSchemeName()); if (sf == null) { throw new UnsupportedSchemeException(host.getSchemeName() + " protocol is not supported"); } final InetAddress[] addresses = host.getAddress() != null ? new InetAddress[] { host.getAddress() } : this.dnsResolver.resolve(host.getHostName()); final int port = this.schemePortResolver.resolve(host); for (int i = 0; i < addresses.length; i++) { final InetAddress address = addresses[i]; final boolean last = i == addresses.length - 1; Socket sock = sf.createSocket(context); sock.setSoTimeout(socketConfig.getSoTimeout()); sock.setReuseAddress(socketConfig.isSoReuseAddress()); sock.setTcpNoDelay(socketConfig.isTcpNoDelay()); sock.setKeepAlive(socketConfig.isSoKeepAlive()); if (socketConfig.getRcvBufSize() > 0) { sock.setReceiveBufferSize(socketConfig.getRcvBufSize()); } if (socketConfig.getSndBufSize() > 0) { sock.setSendBufferSize(socketConfig.getSndBufSize()); } final int linger = socketConfig.getSoLinger(); if (linger >= 0) { sock.setSoLinger(true, linger); } conn.bind(sock); final InetSocketAddress remoteAddress = new InetSocketAddress(address, port); if (this.log.isDebugEnabled()) { this.log.debug("Connecting to " + remoteAddress); } try { sock = sf.connectSocket( connectTimeout, sock, host, remoteAddress, localAddress, context); conn.bind(sock); if (this.log.isDebugEnabled()) { this.log.debug("Connection established " + conn); } return; } catch (final SocketTimeoutException ex) { if (last) { throw new ConnectTimeoutException(ex, host, addresses); } } catch (final ConnectException ex) { if (last) { final String msg = ex.getMessage(); throw "Connection timed out".equals(msg) ? new ConnectTimeoutException(ex, host, addresses) : new HttpHostConnectException(ex, host, addresses); } } catch (final NoRouteToHostException ex) { if (last) { throw ex; } } if (this.log.isDebugEnabled()) { this.log.debug("Connect to " + remoteAddress + " timed out. " + "Connection will be retried using another IP address"); } } } }
DefaultHttpClientConnectionOperator的connect先通过getSocketFactoryRegistry获取Lookup<ConnectionSocketFactory>
,再通过它获取ConnectionSocketFactory,之后通过dnsResolver解析地址,再通过schemePortResolver解析port,然后通过ConnectionSocketFactory创建socket,并根据socketConfig设置socket的参数,最后执行connectSocket,并绑定到conn
connectSocket
org/apache/http/conn/socket/PlainConnectionSocketFactory.java
public class PlainConnectionSocketFactory implements ConnectionSocketFactory { public static final PlainConnectionSocketFactory INSTANCE = new PlainConnectionSocketFactory(); public static PlainConnectionSocketFactory getSocketFactory() { return INSTANCE; } public PlainConnectionSocketFactory() { super(); } @Override public Socket createSocket(final HttpContext context) throws IOException { return new Socket(); } @Override public Socket connectSocket( final int connectTimeout, final Socket socket, final HttpHost host, final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpContext context) throws IOException { final Socket sock = socket != null ? socket : createSocket(context); if (localAddress != null) { sock.bind(localAddress); } try { sock.connect(remoteAddress, connectTimeout); } catch (final IOException ex) { try { sock.close(); } catch (final IOException ignore) { } throw ex; } return sock; } }
PlainConnectionSocketFactory的createSocket直接new一个socket,其connectSocket方法则执行sock.connect
socketConfig
resolveSocketConfig
org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
private SocketConfig resolveSocketConfig(final HttpHost host) { SocketConfig socketConfig = this.configData.getSocketConfig(host); if (socketConfig == null) { socketConfig = this.configData.getDefaultSocketConfig(); } if (socketConfig == null) { socketConfig = SocketConfig.DEFAULT; } return socketConfig; }
PoolingHttpClientConnectionManager的resolveSocketConfig先是从configData根据指定host获取socketConfig,若为null则再从configData获取默认的socketConfig,若为null则返回默认的socketConfig
setSocketConfig
org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
public void setDefaultSocketConfig(final SocketConfig defaultSocketConfig) { this.configData.setDefaultSocketConfig(defaultSocketConfig); } public void setSocketConfig(final HttpHost host, final SocketConfig socketConfig) { this.configData.setSocketConfig(host, socketConfig); }
PoolingHttpClientConnectionManager提供了setDefaultSocketConfig、setSocketConfig方法
SocketConfig.DEFAULT
org/apache/http/config/SocketConfig.java
public class SocketConfig implements Cloneable { public static final SocketConfig DEFAULT = new Builder().build(); //...... public static class Builder { private int soTimeout; private boolean soReuseAddress; private int soLinger; private boolean soKeepAlive; private boolean tcpNoDelay; private int sndBufSize; private int rcvBufSize; private int backlogSize; Builder() { this.soLinger = -1; this.tcpNoDelay = true; } //...... } }
默认的socketConfig,除了tcpNoDelay为true,其他的都为false,然后soLinger为-1
小结
HttpClientConnectionOperator定义了connect及upgrade方法,它有一个默认的实现类为DefaultHttpClientConnectionOperator;DefaultHttpClientConnectionOperator的connect先通过getSocketFactoryRegistry获取Lookup<ConnectionSocketFactory>
,再通过它获取ConnectionSocketFactory,之后通过dnsResolver解析地址,再通过schemePortResolver解析port,然后通过ConnectionSocketFactory创建socket,并根据socketConfig设置socket的参数,最后执行connectSocket,并绑定到conn;默认的socketConfig,除了tcpNoDelay为true,其他的都为false,然后soLinger为-1。
以上就是httpclient connect连接请求方法源码解读的详细内容,更多关于httpclient connect连接请求的资料请关注脚本之家其它相关文章!
您可能感兴趣的文章:
- httpclient getPoolEntryBlocking连接池方法源码解读
- httpclient staleConnectionCheckEnabled获取连接流程解析
- 解读httpclient的validateAfterInactivity连接池状态检测
- httpclient的disableConnectionState方法工作流程
- 探索HttpClient中的close方法及其对连接的影响
- HttpClient的RedirectStrategy重定向处理核心机制
- HttpClient HttpRoutePlanner接口确定请求目标路由
- httpclient ConnectionHolder连接池连接保持源码解析