#1.介紹 關於MQTT就不需過多的介紹,網上一大堆。不過支援iOS 推薦以下庫 1.MQTTKit--基於Mosquitto 不過長時間未更新了 2.MQTT-Client-Framework--基於iOS 原生 #2.採坑記錄 本文著重介紹MQTT-Client-Framework的使用和注意事項。 ##1.關於初始化
//帶證書
NSString *certificate = [[NSBundle mainBundle]pathForResource:@"ca" ofType:@"cer"];
MQTTWebsocketTransport *transport = [[MQTTWebsocketTransport alloc]init];
transport.host = self.host;
transport.port = self.port;
transport.tls = YES;
//坑1---release 下預設是NO, 如果你的證書是自簽名證書需要設定為YES ,否則你的release版本將無法通過證書驗證,提示 shakehandfield 。
transport.allowUntrustedCertificates = YES;
//坑2---初始化必須要在主執行緒當中,因為 session的init 方法會預設建立一個 runloop 原始碼中使用的是 currentRunloop. 這個runloop 是用於 encode 和 decode。如果放在子執行緒將無法收到encode 和 decode的回撥。
self.session = [[MQTTSession alloc] initWithClientId:self.uuid userName:self.username password:self.password keepAlive:50 cleanSession:YES];
self.session.transport = transport;
self.session.delegate = self;
self.session.certificates = @[[NSData dataWithContentsOfFile:certificate]];
複製程式碼
##2.釋出 坑3---放在子執行緒,過多的資料讀寫全部放在主執行緒會阻塞。 ##3.取消訂閱和訂閱 ##4.關於代理
//有新訊息的回撥
- (void)newMessage:(LDSMQTTSession *)session
data:(NSData *)data
onTopic:(NSString *)topic
qos:(MQTTQosLevel)qos
retained:(BOOL)retained
mid:(unsigned int)mid;
//連線狀態改變的回撥
- (void)handleEvent:(LDSMQTTSession *)session event:(LDSMQTTSessionEvent)eventCode error:(NSError *)error;
//連線被拒絕的回撥--用於連線被踢掉,或證書無法驗證通過等原因查詢,可做賬號密碼校驗
- (void)connectionRefused:(LDSMQTTSession *)session error:(NSError *)error;
其他不過多介紹了
複製程式碼
##4.關於斷開重連策略
// 重連機制
-(void) reConnect {
// 2^5=64
if (reConnecTime>64) {
NSLog(@"reconnect timeout !");
if (_timer) {
dispatch_cancel(_timer);
_timer = nil;
}
return;
}
if (_timer==nil) {
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(_timer, ^{
reConnecTimeCount++;
if (reConnecTimeCount==reConnecTime) {
[self.session disconnect];
[self connect];
reConnecTimeCount = 0;
dispatch_cancel(_timer);
_timer = nil;
}
});
dispatch_resume(_timer);
}
NSLog(@"重連間隔時間 %f",reConnecTime);
reConnecTime *=2;
}
複製程式碼
##5.請求超時和重試機制 目前個人想到2種解決方案,1.由每個請求自己去檢查自己是否請求超時,2.由轉換層統一處理。 個人更傾向於方案2.
//遍歷我請求等待佇列的req
for (int i = (int)ws.routingRequests.count - 1; i >= 0; i --) {
LDSSktBaseRequest *req = nil;
req = [ws.routingRequests objectAtIndex:i];
//超時處理
如果req 的請求到期時間到當前時間的時間差 + (req 的超時時間*req 的重試次數) <0 ,那麼請求超時
if ([req.timeoutDate timeIntervalSinceNow]<0-req.timeIntervalOut*req.retryCount) {
if (req.delegate && [req.delegate respondsToSelector:@selector(ldsSktBaseRequestServiceDidReceiveResponse:error:)]) {
[req.delegate ldsSktBaseRequestServiceDidReceiveResponse:req error:[NSError errorWithDomain:@"com.ldsSocket" code:-999 userInfo:@{NSLocalizedDescriptionKey: @"Request Timeout"}]];
[ws removeRequest:req];
NSLog(@"Request Timeout\n %@ ",[req params]);
continue;
}
}
}
複製程式碼
##6.請求等待佇列和請求傳送等待佇列 每個MQTT session 我維護了一個請求等待佇列(等待回覆的請求,如果當前連線狀態不是連線成功 且 等待傳送佇列不包含,就放入傳送佇列,否則加入回覆佇列中)和一個請求等待傳送佇列(因連線斷開或還未開始連線時傳送的請求,一旦連線成功就把該佇列的請求全部發出)