Mqtt Java源码分析1 Connect

Connect分析
调用MqttClient的connect方法会触发:MqttAsyncClient的connect方法,其实源码是写了一套,MqttClient复用了MqttAsyncClient的代码。
public IMqttToken connect(MqttConnectOptions options, Object userContext, IMqttActionListener callback)
throws MqttException, MqttSecurityException {
final String methodName = “connect”;
if (comms.isConnected()) {
throw ExceptionHelper.createMqttException(MqttException.REASON_CODE_CLIENT_CONNECTED);
}
if (comms.isConnecting()) {
throw new MqttException(MqttException.REASON_CODE_CONNECT_IN_PROGRESS);
}
if (comms.isDisconnecting()) {
throw new MqttException(MqttException.REASON_CODE_CLIENT_DISCONNECTING);
}
if (comms.isClosed()) {
throw new MqttException(MqttException.REASON_CODE_CLIENT_CLOSED);
}

    this.connOpts = options;
    this.userContext = userContext;
    final boolean automaticReconnect = options.isAutomaticReconnect();


    comms.setNetworkModules(createNetworkModules(serverURI, options));//见下面Code1
    comms.setReconnectCallback(new MqttCallbackExtended() {

        public void messageArrived(String topic, MqttMessage message) throws Exception {
        }
        public void deliveryComplete(IMqttDeliveryToken token) {
        }
        public void connectComplete(boolean reconnect, String serverURI) {
        }

        public void connectionLost(Throwable cause) {
            if(automaticReconnect){
                    // Automatic reconnect is set so make sure comms is in resting state
                    comms.setRestingState(true);
                    reconnecting = true;
                    startReconnectCycle();
                }
        }
    });


    // Insert our own callback to iterate through the URIs till the connect succeeds
    MqttToken userToken = new MqttToken(getClientId());
    ConnectActionListener connectActionListener = new ConnectActionListener(this, persistence, comms, options, userToken, userContext, callback, reconnecting);
    userToken.setActionCallback(connectActionListener);
    userToken.setUserContext(this);

    // If we are using the MqttCallbackExtended, set it on the connectActionListener
    if(this.mqttCallback instanceof MqttCallbackExtended){
        connectActionListener.setMqttCallbackExtended((MqttCallbackExtended)this.mqttCallback);
    }

    comms.setNetworkModuleIndex(0);
    connectActionListener.connect();// 调用连接API,参加Code3

    return userToken;
}

Code1 ClientComms根据SSL/TCP/WS等创建Socket连接
大意就是根据address以及MqttConnectOptions options里面封装的ServerURI,如果options里面封装的serverURI为空或者数组length为0,则根据address创建一个NetworkModule实例,否则根据options里面的serverURI创建所有的NetworkModule实例,并存储到networkModules数组中去。
/**
* Factory method to create an array of network modules, one for
* each of the supplied URIs
*
* @param address the URI for the server.
* @return a network module appropriate to the specified address.
*/
// may need an array of these network modules

protected NetworkModule[] createNetworkModules(String address, MqttConnectOptions options) throws MqttException, MqttSecurityException {
    final String methodName = "createNetworkModules";
    NetworkModule[] networkModules = null;
    String[] serverURIs = options.getServerURIs();
    String[] array = null;
    if (serverURIs == null) {
        array = new String[]{address};
    } else if (serverURIs.length == 0) {
        array = new String[]{address};
    } else {
        array = serverURIs;
    }

    networkModules = new NetworkModule[array.length];
    for (int i = 0; i < array.length; i++) {
        networkModules[i] = createNetworkModule(array[i], options);//分析一下createNetworkModule
    }

    return networkModules;
}

首先我们需要知道NetworkModule接口封装的是相关Socket网络操作,获取输入输出流,启动关闭Socket连接模块操作
public interface NetworkModule {
public void start() throws IOException, MqttException;

public InputStream getInputStream() throws IOException;

public OutputStream getOutputStream() throws IOException;

public void stop() throws IOException;

public String getServerURI();

}
//根据一个地址创建出一个NetworkModule
private NetworkModule createNetworkModule(String address, MqttConnectOptions options) throws MqttException, MqttSecurityException {
final String methodName = “createNetworkModule”;

    NetworkModule netModule;
    String shortAddress;
    String host;
    int port;
    SocketFactory factory = options.getSocketFactory();

    int serverURIType = MqttConnectOptions.validateURI(address);//查询到底是SSL,TCP,WEBSOCKET等还是什么连接

    switch (serverURIType) {
    case MqttConnectOptions.URI_TYPE_TCP :
        shortAddress = address.substring(6);
        host = getHostName(shortAddress);
        port = getPort(shortAddress, 1883);

//如果MqttConnectOptions没有设置SocketFactory则建立一个默认的SocketFactory,通过SocketFactory.getDefault();方法获取。
if (factory == null) {
factory = SocketFactory.getDefault();
}
else if (factory instanceof SSLSocketFactory) {
throw ExceptionHelper.createMqttException(MqttException.REASON_CODE_SOCKET_FACTORY_MISMATCH);
}
//创建一个TCPNetworkModule实例(实现NetworkModule接口)参见Code1.1
netModule = new TCPNetworkModule(factory, host, port, clientId);
((TCPNetworkModule)netModule).setConnectTimeout(options.getConnectionTimeout());
break;
case MqttConnectOptions.URI_TYPE_SSL:
shortAddress = address.substring(6);
host = getHostName(shortAddress);
port = getPort(shortAddress, 8883);
SSLSocketFactoryFactory factoryFactory = null;
if (factory == null) {
// try {
factoryFactory = new SSLSocketFactoryFactory();
Properties sslClientProps = options.getSSLProperties();
if (null != sslClientProps)
factoryFactory.initialize(sslClientProps, null);
factory = factoryFactory.createSocketFactory(null);
// }
// catch (MqttDirectException ex) {
// throw ExceptionHelper.createMqttException(ex.getCause());
// }
}
else if ((factory instanceof SSLSocketFactory) == false) {
throw ExceptionHelper.createMqttException(MqttException.REASON_CODE_SOCKET_FACTORY_MISMATCH);
}

        // Create the network module...
        netModule = new SSLNetworkModule((SSLSocketFactory) factory, host, port, clientId);
        ((SSLNetworkModule)netModule).setSSLhandshakeTimeout(options.getConnectionTimeout());
        // Ciphers suites need to be set, if they are available
        if (factoryFactory != null) {
            String[] enabledCiphers = factoryFactory.getEnabledCipherSuites(null);
            if (enabledCiphers != null) {
                ((SSLNetworkModule) netModule).setEnabledCiphers(enabledCiphers);
            }
        }
        break;
    case MqttConnectOptions.URI_TYPE_WS:
        shortAddress = address.substring(5);
        host = getHostName(shortAddress);
        port = getPort(shortAddress, 80);
        if (factory == null) {
            factory = SocketFactory.getDefault();
        }
        else if (factory instanceof SSLSocketFactory) {
            throw ExceptionHelper.createMqttException(MqttException.REASON_CODE_SOCKET_FACTORY_MISMATCH);
        }
        netModule = new WebSocketNetworkModule(factory, address, host, port, clientId);
        ((WebSocketNetworkModule)netModule).setConnectTimeout(options.getConnectionTimeout());
        break;
    case MqttConnectOptions.URI_TYPE_WSS:
        shortAddress = address.substring(6);
        host = getHostName(shortAddress);
        port = getPort(shortAddress, 443);
        SSLSocketFactoryFactory wSSFactoryFactory = null;
        if (factory == null) {
            wSSFactoryFactory = new SSLSocketFactoryFactory();
                Properties sslClientProps = options.getSSLProperties();
                if (null != sslClientProps)
                    wSSFactoryFactory.initialize(sslClientProps, null);
                factory = wSSFactoryFactory.createSocketFactory(null);

        }
        else if ((factory instanceof SSLSocketFactory) == false) {
            throw ExceptionHelper.createMqttException(MqttException.REASON_CODE_SOCKET_FACTORY_MISMATCH);
        }

        // Create the network module... 
        netModule = new WebSocketSecureNetworkModule((SSLSocketFactory) factory, address, host, port, clientId);
        ((WebSocketSecureNetworkModule)netModule).setSSLhandshakeTimeout(options.getConnectionTimeout());
        // Ciphers suites need to be set, if they are available
        if (wSSFactoryFactory != null) {
            String[] enabledCiphers = wSSFactoryFactory.getEnabledCipherSuites(null);
            if (enabledCiphers != null) {
                ((SSLNetworkModule) netModule).setEnabledCiphers(enabledCiphers);
            }
        }
        break;
    case MqttConnectOptions.URI_TYPE_LOCAL :
        netModule = new LocalNetworkModule(address.substring(8));
        break;
    default:
        // This shouldn't happen, as long as validateURI() has been called.
        netModule = null;
    }
    return netModule;
}

Code1.1
/**
* A network module for connecting over TCP.
*/
public class TCPNetworkModule implements NetworkModule {

protected Socket socket;
private SocketFactory factory;
private String host;
private int port;
private int conTimeout;

/**
 * Constructs a new TCPNetworkModule using the specified host and
 * port.  The supplied SocketFactory is used to supply the network
 * socket.
 */
public TCPNetworkModule(SocketFactory factory, String host, int port, String resourceContext) {
    this.factory = factory;
    this.host = host;
    this.port = port;

}

/**
 * Starts the module, by creating a TCP socket to the server.建立连接,connect server
 */
public void start() throws IOException, MqttException {
    final String methodName = "start";
    try {
        SocketAddress sockaddr = new InetSocketAddress(host, port);
        socket = factory.createSocket();
        socket.connect(sockaddr, conTimeout*1000);

    }
    catch (ConnectException ex) {
        throw new MqttException(MqttException.REASON_CODE_SERVER_CONNECT_ERROR, ex);
    }
}

public InputStream getInputStream() throws IOException {
    return socket.getInputStream();
}

public OutputStream getOutputStream() throws IOException {
    return socket.getOutputStream();
}

/**
 * Stops the module, by closing the TCP socket.
 */
public void stop() throws IOException {
    if (socket != null) {
        socket.close();
    }
}

/**
 * Set the maximum time to wait for a socket to be established
 * @param timeout
 */
public void setConnectTimeout(int timeout) {
    this.conTimeout = timeout;
}

public String getServerURI() {
    return "tcp://" + host + ":" + port;
}

}
同理可以分析SSLNetworkModule等等的实现,这里就是为了获取一个Socket的操作工具模块。

Code3 ConnectActionListener
首先分析ConnectActionListener类,
public ConnectActionListener(
MqttAsyncClient client,
MqttClientPersistence persistence,
ClientComms comms,
MqttConnectOptions options,
MqttToken userToken,
Object userContext,
IMqttActionListener userCallback,
boolean reconnect) {
this.persistence = persistence;
this.client = client;
this.comms = comms;
this.options = options;
this.userToken = userToken;
this.userContext = userContext;
this.userCallback = userCallback;
this.originalMqttVersion = options.getMqttVersion();
this.reconnect = reconnect;
}
将persistence,client,comms,options,userToken等对象通过构造函数传入,创建ConnectionActionListener.这个类是用来处理连接的,他调用connect()方法时使用的是自己内部的回掉函数,然后在自己的回调函数里面再调用userCallback的回调函数。具体如下:
/**
* Start the connect processing
* @throws MqttPersistenceException
*/
public void connect() throws MqttPersistenceException {
MqttToken token = new MqttToken(client.getClientId());
token.setActionCallback(this);//设置自己为当前的回调函数
token.setUserContext(this);

persistence.open(client.getClientId(), client.getServerURI());

if (options.isCleanSession()) {
  persistence.clear();
}
if (options.getMqttVersion() == MqttConnectOptions.MQTT_VERSION_DEFAULT) {
  options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
}

try {
  comms.connect(options, token);//真正连接的connect调用的是ClientComms的connect方法;
}
catch (MqttException e) {
  onFailure(token, e);
}

}
我们可以知道当执行comms.connect()之后成功会触发ConnectActionListener的onSuccess回调,失败则会触发ConnectActionListener的onFailure回调,这里我们只分析一个,onSuccess回调
/**
* If the connect succeeded then call the users onSuccess callback
*
* @param token
*/
public void onSuccess(IMqttToken token) {
if (originalMqttVersion == MqttConnectOptions.MQTT_VERSION_DEFAULT) {
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_DEFAULT);
}
userToken.internalTok.markComplete(token.getResponse(), null);
userToken.internalTok.notifyComplete();
userToken.internalTok.setClient(this.client); // fix bug 469527 - maybe should be set elsewhere?

if(reconnect){
    comms.notifyReconnect();
}

if (userCallback != null) {
  userToken.setUserContext(userContext);
  userCallback.onSuccess(userToken);//从这里我们可以知道会调用传给ConnectionActionListener的回调.这个所谓的用户层的回调,就是当我们调用MqttAsyncClient 或者 MqttClient mqttAsyncClient.setCallback(new MqttCallback() {里面的方法。
}

if(mqttCallbackExtended != null){
    String serverURI = comms.getNetworkModules()[comms.getNetworkModuleIndex()].getServerURI();
    mqttCallbackExtended.connectComplete(reconnect, serverURI);
}

}

你可能感兴趣的:(Mqtt分析,Mqtt)