基于MQTT的推送,连接服务器问题

最近,项目中要实现基于MQTT协议IM功能。此时,觉得头疼,赶紧问问MQTT的官网,看看这玩意到底是怎么一回事。看过之后,哇哦,还挺神奇的,了解之后,我们自己就可以开发即时通讯了,还用什么第三方的类库啊。好了,闲话不多说,我们进入正题吧。

第一:MQTT的简介

MQTT轻量发布订阅消息协议

概览

MQTT是一个轻量的发布订阅模式消息传输协议,专门针对低带宽和不稳定网络环境的物联网应用设计。

MQTT官网: http://mqtt.org

MQTT V3.1.1协议规范: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html

特点

1.开放消息协议,简单易实现
2.发布订阅模式,一对多消息发布
3.基于TCP/IP网络连接
4.1字节固定报头,2字节心跳报文,报文结构紧凑
5.消息QoS支持,可靠传输保证

应用

MQTT协议广泛应用于物联网、移动互联网、智能硬件、车联网、电力能源等领域。

1.物联网M2M通信,物联网大数据采集
2.Android消息推送,WEB消息推送
3.移动即时消息,例如Facebook Messenger
4.智能硬件、智能家具、智能电器
5.车联网通信,电动车站桩采集
6.智慧城市、远程医疗、远程教育
7.电力、石油与能源等行业市场

下面附上MQTT协议的中文连接:http://docs.emqtt.cn/zh_CN/latest/mqtt.html

第二:需要配置的文件

1.在build.gradle文件中添加所需的包。


    compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
    compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'

以为这两个一添加就完了嘛???对,没有,如果只是这样的话,是永远收不到推送的,最关键的就是第二步。
2.在AndroidManifest.xml文件中添加如下代码:

 <service android:name="org.eclipse.paho.android.service.MqttService" />

有人可能会有疑问,还要添加这行嘛,对,没错,必须添加。

现在所有的准备工作做完了,让我们连接服务器吧。

第三:连接服务器

我在代码中,书写了相关的注释,大家看代码,这里就不多解释了,如果有不懂的,可以看看上面的中文连接的MQTT协议。

public class MqttTest {
    private static final String TAG = "MqttTest";
    private static final String MQTT_BROKER = "后台的地址"; // Broker URL or IP Address
    private static final String MQTT_PORT = "端口号"; // Broker Port
    private static final String MQTT_URL_FORMAT = "tcp://%s:%s"; // URL Format normally don't change
    private String myTopic = "test/topic";
    private ScheduledExecutorService scheduler;
    private MqttAsyncClient mqttClient;
    private String userName = "admin"; // 连接的用户名
    private String passWord = "123456"; //连接的密码
    private String mDeviceId = "";       // Device ID, Secure.ANDROID_ID
    private ConnectivityManager mConnectivityManager; // To check for connectivity changes
    private MqttConnectOptions options;
    private Context context;

    public MqttTest(Context context) {
        this.context = context;
    }

    /**
     * 初始化相关数据
     */
    public void init() {
        try {
            //host为主机名,test为clientid即连接MQTT的客户端ID,一般以客户端唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
            String url = String.format(Locale.US, MQTT_URL_FORMAT, MQTT_BROKER, MQTT_PORT);
            String clientId = String.valueOf(System.currentTimeMillis());
            mqttClient = new MqttAsyncClient(url, clientId, new MemoryPersistence());
            //MQTT的连接设置
            options = new MqttConnectOptions();
            //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
            options.setCleanSession(true);
            //设置连接的用户名
            options.setUserName(userName);
            //设置连接的密码
            options.setPassword(passWord.toCharArray());
            // 设置超时时间 单位为秒
            options.setConnectionTimeout(10);
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
            options.setKeepAliveInterval(20);
            //设置回调

            options.setAutomaticReconnect(true);//设置自动重连
//            mqttAsyncClient.connect(connOpts).waitForCompletion();
            mqttClient.setCallback(new MqttCallback() {

                @Override
                public void connectionLost(Throwable cause) {
                    //连接丢失后,一般在这里面进行重连
                    if (isNetworkAvailable()) {
                        reconnectIfNecessary();
                    }
                }

                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    //subscribe后得到的消息会执行到这里面
                    Log.e(TAG, "message=:" + message.toString());
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    //publish后会执行到这里
                    long messageId = token.getMessageId();
                    Log.e(TAG, "messageId=:" + messageId);

                }

            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        mConnectivityManager = (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE);
        context.registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));

    }

    /**
     * Query's the NetworkInfo via ConnectivityManager
     * to return the current connected state
     * 通过ConnectivityManager查询网络连接状态
     *
     * @return boolean true if we are connected false otherwise
     * 如果网络状态正常则返回true反之flase
     */
    private boolean isNetworkAvailable() {
        NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();

        return (info == null) ? false : info.isConnected();
    }

    /**
     * Checkes the current connectivity
     * and reconnects if it is required.
     * 重新连接如果他是必须的
     */
    public synchronized void reconnectIfNecessary() {
        if (mqttClient == null || !mqttClient.isConnected()) {
            connect();
        }
    }

    private void connect() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    mqttClient.connect(options);
                    // 连接成功之后,处理相关逻辑
                } catch (Exception e) {
                    e.printStackTrace();
                    // 连接出错,可以设置重新连接
                }
            }
        }).start();
    }

    /**
     *  调用init() 方法之后,调用此方法。
     */
    public void startReconnect() {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                if (!mqttClient.isConnected() && isNetworkAvailable()) {
                    connect();
                }
            }
        }, 0 * 1000, 10 * 1000, TimeUnit.MILLISECONDS);
    }

    /**
     * Receiver that listens for connectivity chanes
     * via ConnectivityManager
     * 网络状态发生变化接收器
     */
    private final BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i("BroadcastReceiver", "Connectivity Changed...");
            if (!isNetworkAvailable()) {
                Toast.makeText(context, "网络错误", Toast.LENGTH_SHORT).show();
                scheduler.shutdownNow();
            } else {
                startReconnect();
            }
        }
    };
}

嗯,相关连接后台的数据,基本上就这么多,看后天给你返回的数据是怎么样,自己拿上用即可。

最后,加上github的例子,
https://github.com/honeylife/paho.mqtt.javascript,可以下载跑起来,看看相关的例子,逻辑特别严谨。

我会在下面的文章,写即时通讯的相关代码,以及聊天界面的实现,还有图片切换时键盘高度的控制等。

你可能感兴趣的:(Android,Java,即时通讯)