工程中使用tcp長連接來和服務端進行數據傳輸,在IOS平台上,由於蘋果的后台機制,會有以下問題:
當程序退到后台的時候,所有線程被掛起,系統會回收所有的socket資源,那么socket連接就會被關閉,因此無法再進行數據的傳輸:
解決方法:
通過設置以下屬性可以保持socket連接和數據的繼續傳輸
1.需要在Info.plist文件中添加UIBackgroundModes中的VOIP鍵值;
2.設置流屬性
CFReadStreamRef和CFWriteStreamRef通過如下方法設置kCFStreamNetworkServiceType屬性為kCFStreamNetworkServiceTypeVoIP;
CFReadStreamSetProperty(theReadStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
CFWriteStreamSetProperty(theWriteStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
NSInputStream 和NSOutputStream通過如下方法設置NSStreamNetworkServiceType屬性為NSStreamNetworkServiceTypeVoIP;
[self.stream setProperty: NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType];
3.這里有一個問題,就是客戶端是通過心跳來和服務端保持連接,心跳是由定時器觸發的,當我退到后台以后,定時器方法被掛起,那么通過如下設置來在后台運行定時器
1 - (void)applicationDidEnterBackground:(UIApplication *)application{ 2 3 UIApplication* app = [UIApplication sharedApplication]; 4 __block UIBackgroundTaskIdentifier bgTask; 5 bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 6 dispatch_async(dispatch_get_main_queue(), ^{ 7 if (bgTask != UIBackgroundTaskInvalid) 8 { 9 bgTask = UIBackgroundTaskInvalid; 10 } 11 }); 12 }]; 13 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 14 dispatch_async(dispatch_get_main_queue(), ^{ 15 if (bgTask != UIBackgroundTaskInvalid) 16 { 17 bgTask = UIBackgroundTaskInvalid; 18 } 19 }); 20 }); 21 }
