继上个星期以后,这个星期有花了两三天的时间来搞emqtt的ssl/tls加密。html
主流程仍是参考了:https://blog.csdn.net/a704397849/article/details/88885198#commentsedit, 到最后一步用mosquitto_sub订阅消息的时候始终有问题:java
联系了参考文章的做者,而且加了QQ,想不到是个很热情的人。他从新走了一下流程而且肯定是没有问题的,给了我一份客户端的代码:mysql
package com.zkong.mqttssl; import org.eclipse.paho.client.mqttv3.*; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import javax.net.SocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; public class MqttTLSTest { static MqttClientCallback mqttClientCallback = new MqttClientCallback(); static MqttAsyncClient mqttClient = null; static String username = "stan"; //注意这里 填你本身的mqtt帐号密码 static String password = "123456"; //注意这里 填你本身的mqtt帐号密码 //String broker = "tcp://xxx.xx.xxx.xxx:1883"; //注意这里要填本身mqtt服务器所在地址 static String broker = "ssl://192.168.100.117:8883"; //注意这里要填本身mqtt服务器所在地址 public static void main(String[] args) throws InterruptedException { start(); while (true){ Thread.sleep(10000); } } public static void start() { String clientId = "mqttserver" + String.valueOf(System.currentTimeMillis()); try { mqttClient = new MqttAsyncClient(broker, clientId, new MemoryPersistence()); mqttClient.setCallback(mqttClientCallback); //订阅 链接mqtt服务器 subscribeConnect(); //发布 链接mqtt服务器 //... 略 } catch (MqttException me) { System.out.println("reason " + me.getReasonCode()); System.out.println("msg " + me.getMessage()); System.out.println("loc " + me.getLocalizedMessage()); System.out.println("cause " + me.getCause()); System.out.println("excep " + me); me.printStackTrace(); } } public static void subscribeConnect() { System.out.println("订阅链接"); if (mqttClient != null) { try { MqttConnectOptions connOpts = new MqttConnectOptions(); connOpts.setCleanSession(true); connOpts.setMaxInflight(100000); connOpts.setUserName(username); connOpts.setPassword(password.toCharArray()); //ssl 链接 , 这里的 TrustManager 是本身实现的,没有去校验服务端的证书 TrustManager[] trustAllCerts = new TrustManager[1]; TrustManager tm = new MyTM(); trustAllCerts[0] = tm; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, null); SocketFactory factory = sc.getSocketFactory(); connOpts.setSocketFactory(factory); // mqttClient.connect(connOpts, null, new IMqttActionListener() { @Override public void onSuccess(IMqttToken asyncActionToken) { try { //订阅 topic 为test 的消息,消息质量1 mqttClient.subscribe("test", 1); } catch (MqttException me) { System.out.println("reason " + me.getReasonCode()); System.out.println("msg " + me.getMessage()); System.out.println("loc " + me.getLocalizedMessage()); System.out.println("cause " + me.getCause()); System.out.println("excep " + me); me.printStackTrace(); } } @Override public void onFailure(IMqttToken asyncActionToken, Throwable exception) { System.out.println("mqtt 没有链接上:" + exception.getMessage()); exception.printStackTrace(); } }); } catch (MqttException me) { System.out.println("reason " + me.getReasonCode()); System.out.println("msg " + me.getMessage()); System.out.println("loc " + me.getLocalizedMessage()); System.out.println("cause " + me.getCause()); System.out.println("excep " + me); me.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } } } //MyTM 是本身实现的认证管理类,里面并有校验服务端的证书就返回true,永久成功! static class MyTM implements TrustManager, X509TrustManager { @Override public X509Certificate[] getAcceptedIssuers() { return null; } public boolean isServerTrusted(X509Certificate[] certs) { return true; } public boolean isClientTrusted(X509Certificate[] certs) { return true; } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { return; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException { return; } } public static class MqttClientCallback implements MqttCallback{ @Override public void connectionLost(Throwable arg0) { System.out.println("mqtt 失去了链接"); } @Override public void deliveryComplete(IMqttDeliveryToken arg0) { System.out.println("mqtt 发送完成!"); } @Override public void messageArrived(String topic, MqttMessage message) throws Exception { String content = new String(message.getPayload(), "utf-8"); System.out.println("收到mqtt消息,topic: "+topic+" ,content: "+content); } } }
用这份客户端代码订阅消息,是没有问题的,由于个人服务器开启了基于mysql的认证,因此必须提供username和password。sql
要完全走通的,估计还得找一台干净的机器从新安装emqtt。windows
有些问题在此记录一下:服务器
关于mosquittoeclipse
它跟emqtt同样,自己也是一个mqtt的broker,在windows上安装完以后做为一个服务存在,当它处于启动状态时,会占掉1883端口致使emqtt没法彻底启动,能够在Windows的服务管理中将其关闭:async
Centos7上安装openssltcp
http://www.javashuo.com/article/p-muqouusg-eb.htmlide
Centos7上安装mosquitto
http://www.javashuo.com/article/p-mppgavlk-mw.html
未走通流程:
双向认证:https://blog.csdn.net/zljintan/article/details/83619309
自带证书验证(使用MQTTBox做为客户端):http://www.javashuo.com/article/p-nbzatlbi-gq.html