iOS應用中通過設置VOIP模式實現休眠狀態下socket的長連接

如果你的應用程序需要在設備休眠的時候還能夠收到服務器端發送的消息,那我們就可以藉助VOIP的模式來實現這一需求。但是如果的應用程序並不是正真的VOIP應用,那當你把你的應用提交到AppStore的時候基本上會被蘋果Reject. 但是如果你的應用是企業內部發布的或者你只想瞭解其中的原理,那該文也許對您會有所幫助。

一、在iOS中如何應用VOIP
VOIP程序需要穩定的網絡去連接和它相關的服務,這樣它才能接到來電和其他相關的數據。系統允許VOIP程序被掛斷並提供組件去監聽它們的sockets,而不是在任意時候都處於喚醒狀態。設置VOIP應用程序步驟如下:

A、 添加UIBackgroundModes中的VOIP鍵值


大多數VOIP應用需要設置後臺audio 應用去傳遞音頻,因此你應該設置audio 和voip兩個鍵值。
如果只是想通過VOIP來達到socket在休眠狀態下維持長連接那只需要象上圖一樣設置VOIP即可。

B、 爲VOIP設置一個應用程序socket
爲了使應用程序在後臺時保持穩定的連接,你必須tag你的主 通訊socket專門應用於VOIP,tagging這個socket來告訴系統,它必須在你的應用程序中斷時接管這個socket。這個切換本身對於你 的應用程序時透明的,當新的數據到達socket的時候,系統會喚醒應用程序,並將socket的控制權返回給應用程序,這樣應用程序就可以處理新來的數據。

你只需要tag用於voip服務的socket,這個 socket用來接收來電或者其他相關的數據來保持你的VOIP服務的連接。根據收到的信息,這個socket要決定下一步的動作。比如一個來電,你會想 彈出一個本地的通知來告知用戶;對於其他不是那麼關鍵的數據,你可能會想悄悄的處理這些數據並讓系統將應用程序重新中斷。

在IOS中,sockets是用流或者更高級的結構,設置一個VOIP的socket,你只需要在通常的設置中添加一個特殊的key來標明這個接口是用於連接VOIP服務的,下表列出了流的接口和設置:

設置流接口用於voip接口

1、NSInputStream 和NSOutputStream 
對於 Cocoa streams, 使用 setProperty:forKey: 方法添加

NSStreamNetworkServiceType  
屬性給 stream.   
改屬性的值設爲  
NSStreamNetworkServiceTypeVoIP.  

2、NSURLRequest 
對於 URL loading system, 使用 setNetworkServiceType:
method of your NSMutableURLRequest object to set the network service  
type of the request. The service type should be set to  
NSURLNetworkServiceTypeVoIP. 

3、CFReadStreamRef和CFWriteStreamRef
For Core Foundation streams, use the CFReadStreamSetProperty or  
CFWriteStreamSetProperty function to add the kCFStreamNetwork-  
ServiceType property to the stream. The value for this property should be  
set to kCFStreamNetworkServiceTypeVoIP. 
(注意:當設置socket的時候,你需要在你的主信號通道中設置合適的service type key。當設置聲道時,不需要設置這個key)

由於,VOIP應用程序需要一直運行以確保收到來電,所以如果程 序通過一個非零的exit code退出,系統將自動重啓這個應用程序(這種退出方式可以發生在內存壓力大時終止程序運行)。儘管如此,中斷應用程序會release所有的 sockets,包括那個用於連接voip 服務的socket。因此,當程序運行時,它需要一直從頭創建socket。

C、 在移出後臺之前,調用setKeepAliveTimeout:handler:方法去建立一個定期執行的handler,你的應用程序可以運行這個handler來保持服務的連接
爲了防止斷連,voip程序需要定期被喚醒去檢查它的服務。爲了容易實現這個行爲,IOS通過使用(UIApplication setKeepAliveTimeout:handler:)方法建立一個特殊的句柄。你可以在 applicationDidEnterBackground方法中建立該句柄。一旦建立,系統至少會在超時之前調用該句柄一次,來喚醒你的應用程序。

這個keep-alive handler在後臺執行,必須儘快的返回參數,它有最多30秒的時間來執行所需的任務,如果這段時間內句柄沒有返回,那麼系統將終止應用程序。

當你建立了handler之後,確定應用程序所需的最大超時。系統保證會在最大超時之前調用handler,但是這個時間是不確定的,所以你的handler必須在你申明的超時之前做好執行程序的準備。

二、通過GCDAsyncSocket來實現休眠狀態下的長連接:

1、在創建socket並且成功連接上遠程服務器的delegate中執行下述代碼
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)connectedPort{
    [socket performBlock:^{
        [socket enableBackgroundingOnSocket];
    }];
}



2、在ApplicationDidEnterBackground方法中調用setKeepAliveTimeOut以保持長連接
BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
 if (backgroundAccepted)
 {
      NSLog(@"VOIP backgrounding accepted");
 }



參考:
1、XMPP中長連接問答

2、GCDAsyncSocket實現後臺長連接的VOIP問答

3、後臺運行(內容比較雜,但還是很有參考價值)

4、有一篇國內的關於VOIP以及後臺程序的博文(內容還是比較雜--還是英文的,估計只能由博主自己看懂,僅做參考)
http://blog.csdn.net/gnicky/article/details/7452418

5、iOS socket編程基礎

6、一篇StackOverflow.com中的問答,其中對iOS中對VOIP的解釋比較詳細
If you want to let your VOIP application run in background , except those base settings in plist file, you need a TCP socket who's property is set to VOIP, than the iOS system will take care this socket for you, when your application enter background , every thing was 'sleep' except that tcp socket. and if VOIP server send some data thought that TCP socket, your application will be awake up for 10 secs. during this time, you can post a local notification.

Only Tcp socket can be set as VOIP Socket. But from i know , mostly VOIP application are based on UDP socket. if you do not want to separate the control socket from the data socket. you should create another tcp socket which is focus on 'awake' your application , and from my personal experience , it's very hard to keep this 'awake' signal and the real sip control signal synchronize, the application always miss the sip invite request.

So,the best way is separating the sip control single from the UDP data socket , make it as a tcp socket , this is the best solution , but never use tcp socket to transfer voice data.

Another dirty way: keep the application awake all the time. As i said , each TCP single the application received thought that 'VOIP' tcp socket , will keep application awake for 10 seconds, so at the end of this duration(after 9 secs) , you can send a response to the server to ask for another signal , when the next signal arrived, the application will be awake again,after 9 secs , send response again. keep doing this, your application will awake forever.

7.CocoaAsyncSocket

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章