connect方法分析

2,connect方法

HttpURLConnectionImpl的connect方法如下,

public final void connect() throws IOException {
    initHttpEngine();
    boolean success;
    do {
      success = execute(false);
    } while (!success);
}

首先调用initHttpEngine方法构造HttpEngine对象,然后调用execute方法进行连接,

2.1 构造HttpEngine对象

HttpURLConnectionImpl的initHttpEngine方法如下,

httpEngine = newHttpEngine(method, null, null, null);

在newHttpEngine方法的最后会构造HttpEngine对象,

return new HttpEngine(engineClient, request, bufferRequestBody, true, false, connection, null,
    requestBody, priorResponse);

2.2 execute连接

调用流程图如下,


HttpURLConnectionImpl的execute方法主要逻辑如下,
try {
      httpEngine.sendRequest();

调用HttpEngine对象的sendRequest发送请求,在该方法中会进行连接,

if (connection == null) {
   connect();
}

如果Connection对象connection为空,就调用connect方法进行连接, connect方法主要逻辑如下,

1,首先调用createAddress创建Address对象,

address = createAddress(client, networkRequest);

2,然后调用nextConnection方法创建Connection对象并进行连接,

connection = nextConnection();

nextConnection方法如下,

Connection connection = createNextConnection();
Internal.instance.connectAndSetOwner(client, connection, this, networkRequest);

首先调用createNextConnection方法构造Connection对象,然后调用Internal的connectAndSetOwner方法进行连接。

Internal是一个abstract类,定义如下,

public abstract class Internal {

有一个static变量instance,

public static Internal instance;

现在问题是哪个类继承了Internal并且实现了对应的方法呢?

在源码下面全局搜索,居然没有类继承Internal!  后来才发现,是在OkHttpClient中内部匿名实现的。

并且OkHttpClient是在HttpHandler的createHttpOkUrlFactory方法中构造的,

OkHttpClient client = new OkHttpClient();

Internal在OkHttpClient是一个static的代码块,

Internal.instance = new Internal() {
      @Override public Transport newTransport(
          Connection connection, HttpEngine httpEngine) throws IOException {
        return connection.newTransport(httpEngine);
      }
•••	

其connectAndSetOwner方法如下,

@Override public void connectAndSetOwner(OkHttpClient client, Connection connection,
    HttpEngine owner, Request request) throws RouteException {
    connection.connectAndSetOwner(client, owner, request);
}

Connection的connectAndSetOwner逻辑如下,

if (!isConnected()) {
      List<ConnectionSpec> connectionSpecs = route.address.getConnectionSpecs();
      connect(client.getConnectTimeout(), client.getReadTimeout(), client.getWriteTimeout(),
          request, connectionSpecs, client.getRetryOnConnectionFailure());
      if (isSpdy()) {
        client.getConnectionPool().share(this);
      }
      client.routeDatabase().connected(getRoute());
}

如果还未连接,则调用connect方法进行连接。

2.3 socket连接

Connection的connect调用流程图如下,


Connection的connect的主要逻辑如下,

1,构造SocketConnector对象,

SocketConnector socketConnector = new SocketConnector(this, pool);

2,构造SocketConnector的内部类ConnectedSocket对象,

if (route.address.getSslSocketFactory() != null) {
    // https:// communication
     connectedSocket = socketConnector.connectTls(connectTimeout, readTimeout, writeTimeout,
     request, route, connectionSpecs, connectionRetryEnabled);
} else {
     // http:// communication.
   if (!connectionSpecs.contains(ConnectionSpec.CLEARTEXT)) {
      throw new RouteException(
          new UnknownServiceException(
             "CLEARTEXT communication not supported: " + connectionSpecs));
   }
  connectedSocket = socketConnector.connectCleartext(connectTimeout, readTimeout, route);
}

如果是https网址请求,就调用SocketConnector的connectTls方法创建ConnectedSocket对象,

否则就调用connectCleartext方法创建ConnectedSocket对象。

3,最后为Connection的变量赋值,

socket = connectedSocket.socket;
handshake = connectedSocket.handshake;
protocol = connectedSocket.alpnProtocol == null
        ? Protocol.HTTP_1_1 : connectedSocket.alpnProtocol;

SocketConnector的connectCleartext方法如下,

public ConnectedSocket connectCleartext(int connectTimeout, int readTimeout, Route route)
      throws RouteException {
    Socket socket = connectRawSocket(readTimeout, connectTimeout, route);
    return new ConnectedSocket(route, socket);
  }

首先调用connectRawSocket方法获取Socket对象,然后利用Socket对象构造并返回ConnectedSocket对象。

connectRawSocket方法的逻辑如下,

Platform platform = Platform.get();
    try {
      Proxy proxy = route.getProxy();
      Address address = route.getAddress();
      Socket socket;
      if (proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP) {
        socket = address.getSocketFactory().createSocket();
      } else {
        socket = new Socket(proxy);
      }
      socket.setSoTimeout(soTimeout);
      platform.connectSocket(socket, route.getSocketAddress(), connectTimeout);

      return socket;
    } catch (IOException e) {
      throw new RouteException(e);
    }

首先获取Socket对象,然后调用Platform的connectSocket方法。

Platform这个类还是有点内涵,先来分析一下。

Platform的get方法如下,

public static Platform get() {
   return PLATFORM;
}

PLATFORM是Platform对象,并且是调用findPlatform方法获取

private static final Platform PLATFORM = findPlatform();

findPlatform方法根据android 系统进行构造Platform对象,

1,如果是android 2.3以上版本,就构造Android对象,

•••
return new Android(setUseSessionTickets, setHostname, trafficStatsTagSocket,
          trafficStatsUntagSocket, getAlpnSelectedProtocol, setAlpnProtocols);

当然Android是Platform的子类,并且是Platform的内部类。

2,否则就构造Platform对象,

return new Platform();

Android对象的connectSocket方法如下,

try {
    socket.connect(address, connectTimeout);
} catch (SecurityException se) {
    // Before android 4.3, socket.connect could throw a SecurityException
    // if opening a socket resulted in an EACCES error.
    IOException ioException = new IOException("Exception in connect");
    ioException.initCause(se);
    throw ioException;
}

其实就是调用socket的connect方法进行连接,如果连接出错则抛出异常。

论述了这么多,本质就是构造Socket对象,并调用Socket对象的connect方法进行连接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值