單向認證,客戶端可以含證書也可以不含證書
一、包含證書方式
1,由於android需要bks格式證書,所以我們需要先生成。
1.1 拿到服務端證書
1.2 下載 bcprov-ext-jdkxxx.jar,把jar放入C:\Program Files\Java\jre1.8.0_131\lib\ext
官網地址:http://www.bouncycastle.org/latest_releases.html
1.3 打開cmd,進入C:\Program Files\Java\jre1.8.0_131\bin目錄
輸入命令:keytool -importcert -trustcacerts -keystore "想生成證書的名字和路徑" -file “服務端證書路徑” -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
2,這樣就生成了我們需要的證書,寫連接函數
public boolean start() {
boolean ret ;
try {
MqttConnectOptions conOpt = new MqttConnectOptions();
// host為主機名,clientid即連接MQTT的客戶端ID,一般以唯一標識符表示,MemoryPersistence設置clientid的保存形式,默認為以內存保存
client = new MqttClient(“ssl://ip:端口號”, clientid, new MemoryPersistence());
SSLContext sc = SSLContext.getInstance("SSL");
KeyStore ts = KeyStore.getInstance("BKS");
//讀取剛才生成的bks文件,還有生成時密鑰庫口令
ts.load(context.getAssets().open("key.bks"), "123456".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory
.getInstance("X509");
tmf.init(ts);
TrustManager[] tm = tmf.getTrustManagers();
sc.init(null, tm, new SecureRandom());
SocketFactory factory = sc.getSocketFactory();
conOpt.setSocketFactory(factory);
// MQTT的連接設置
// 設置是否清空session,這里如果設置為false表示服務器會保留客戶端的連接記錄,這里設置為true表示每次連接到服務器都以新的身份連接
conOpt.setCleanSession(true);
// 設置連接的用戶名
conOpt.setUserName(userName);
// 設置連接的密碼
conOpt.setPassword(NewPassWord.toCharArray());
// 設置超時時間 單位為秒
conOpt.setConnectionTimeout(5);
// 設置會話心跳時間 單位為秒 服務器會每隔1.5*20秒的時間向客戶端發送個消息判斷客戶端是否在線,但這個方法並沒有重連的機制
conOpt.setKeepAliveInterval(20);
// 設置回調
client.setCallback(new PushCallback(context));
MqttTopic topic = client.getTopic(TOPIC);
//setWill方法,如果項目中需要知道客戶端是否掉線可以調用該方法。設置最終端口的通知消息
conOpt.setWill(topic, "close".getBytes(), 0, false);
client.connect(conOpt);
//訂閱消息
int[] Qos = {0,0};
//TOPIC,
String[] topic1 = {TOPIC,"Public"};
client.subscribe(topic1, Qos);
ret=true;
} catch (Exception e) {
ret=false;
e.printStackTrace();
try {
if(client.isConnected())
client.disconnect();
} catch (MqttException e1) {
e1.printStackTrace();
}
}
return ret;
}
再加入發布和接受函數就可以實現收發消息了
二、不含證書方式
不含證書需要跳過證書驗證部分,重寫TrustManager,具體代碼如下
static class miTM implements TrustManager, X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
}
連接函數
public boolean start() {
boolean ret ;
try {
MqttConnectOptions conOpt = new MqttConnectOptions();
// host為主機名,clientid即連接MQTT的客戶端ID,一般以唯一標識符表示,MemoryPersistence設置clientid的保存形式,默認為以內存保存
client = new MqttClient(“ssl://ip:端口號”, clientid, new MemoryPersistence());
TrustManager[] trustAllCerts = new TrustManager[1];
TrustManager tm = new miTM();
trustAllCerts[0] = tm;
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
SocketFactory factory = sc.getSocketFactory();
conOpt.setSocketFactory(factory);
// MQTT的連接設置
// 設置是否清空session,這里如果設置為false表示服務器會保留客戶端的連接記錄,這里設置為true表示每次連接到服務器都以新的身份連接
conOpt.setCleanSession(true);
// 設置連接的用戶名
conOpt.setUserName(userName);
// 設置連接的密碼
conOpt.setPassword(NewPassWord.toCharArray());
// 設置超時時間 單位為秒
conOpt.setConnectionTimeout(5);
// 設置會話心跳時間 單位為秒 服務器會每隔1.5*20秒的時間向客戶端發送個消息判斷客戶端是否在線,但這個方法並沒有重連的機制
conOpt.setKeepAliveInterval(20);
// 設置回調
client.setCallback(new PushCallback(context));
MqttTopic topic = client.getTopic(TOPIC);
//setWill方法,如果項目中需要知道客戶端是否掉線可以調用該方法。設置最終端口的通知消息
conOpt.setWill(topic, "close".getBytes(), 0, false);
client.connect(conOpt);
//訂閱消息
int[] Qos = {0,0};
//TOPIC,
String[] topic1 = {TOPIC,"Public"};
client.subscribe(topic1, Qos);
ret=true;
} catch (Exception e) {
ret=false;
e.printStackTrace();
try {
if(client.isConnected())
client.disconnect();
} catch (MqttException e1) {
e1.printStackTrace();
}
}
return ret;
}