HttpClient源码解析系列三:生成和管理Connection

本文接着上一篇博客继续分析,Connection是如何获取的,先说点基础的上篇分析到MainClientExec类#execute()是主要的执行方法,再看看改方法里面的连接时如何获取的。

下面来看HttpClientConnection怎么生成的。核心的接口就是HttpConnectionFactory

看看 connManager.requestConnection(route, userToken)是由BasicHttpClientConnectionManager的#requestConnection()执行

最终执行的是ManagedHttpClientConnectionFactory的#create()方法

这里要注意,因为返回的是一个连接的对象(构造方法实例化对象),是比较复杂的继承和实现的关系,所有的实现都是通过自己和上面的父类的构造方法来实现的,我们来看一下

主要看看DefaultBHttpClientConnection,里面唯一的两个元素,看到名称就可以猜到应该是request的写和response的解析

其实http请求,最终是通过socket来实现tcp协议,最终还是通过IO的输入输出流来完成数据的传输的,其实后面的源码基本上都是围绕上面的SessionOutPutBuffer和SessionInputBuffer来实现的,后面的代码感觉就是流的操作,只不过再解析头信息的时候早了一些处理(不过不重要);其实可以去看看浏览器时怎么发请求的,我httpClient就是模仿;看看总体的流程图:

后面再说说,生成的连接时如何于socket关联起来的

分界线--------------------------------------------------------------------------

解释一下上图:ConnectionRequest是一个只有返回HttpClientConnection的get()方法的接口,继承了Cancellable接口。

BasicHttpClientConnectionManager实现Cancellable接口

接着点进去看看具体再哪里执行,最终调用的收是BasicHttpClientConnectionManager#connection()。

由上面可以看出来最核心的连接过程最终还是通过ConnectionOperator(连接执行器)来完成的,也就是连接管理器HttpClientConnectionManager来控制ConnectionOperator(连接执行器),最终生成连接的,我们接着下面来看HttpClientConnecitonOperator,这个接口就只有一个实现,即DefaultHttpClientConnectionOperator,所以上面ConnectionOperator#connect()执行到了DefaultHttpClientConnectionOperator#connect(),下面我们来分析一下:

 public void connect(
            final ManagedHttpClientConnection conn,
            final HttpHost host,
            final InetSocketAddress localAddress,
            final int connectTimeout,
            final SocketConfig socketConfig,
            final HttpContext context) throws IOException {
        // 从上下文中获取注册的字段SOCKET_FACTORY_REGISTRY,默认http.socket-factory-registry
        final Lookup<ConnectionSocketFactory> registry = getSocketFactoryRegistry(context);
        // 根据Scheme(Http,Https等)默认的http,生成不一样的socket的连接工厂
        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);
        // 生成socket用于通信传输
        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);
            }
            // 真正的连接过程,也就是新建Socket并绑定到HttpClientConnection上的过程
            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);
         ...........
         ...........
        }

上面代码中ConnectionSocketFactory也只有两个实现:PlainConnectionSocketFactory,SSLConnectionSocketFactory(实现了LayeredConnectionSocketFactory,继承自ConnectionSocketFactory)。
PlainConnectionSocketFactory是用于创建非HTTPS连接的,代码很简单,本质上就是new Socket(); (关于Socket编程,我自己都没研究,空了要研究一下,研究好了再说,总体来说其实就是基于io流的传输,里面源码也涉及到了,后面如果分析到了就简单说一下,socket研究深了感觉很伤脑子。。。。);而SSLConnectionSocketFactory就是在创建Socket前后有很多SSL相关的操作,总之就是各种安全加密相关的,这里不详细说明了。

其实DefaultHttpClientConnectionOperator#connect()本身只做一件事情,就是处理Connection和Socket的关系,将他们绑定起来,这也是Connection管理的一部分,我认为直接集成到Manager管理器中也是可以的,为什么没有这么做,可能是希望功能更加细化,更方便管理和拓展。

大概就这样吧,都是自己学习的分析,可能很多地方分析的有问题,欢迎指点;HttpClient其实现在用的比较少,因为其他的开源的通信软件很多,不过基本上原理都是模仿客户端来发送http请求的,貌似Dubbo也是在此基础上的,因为现在用的Spring的技术栈多点,后面也准备系统的学一下Dubbo。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值