pra*_*epa 20 sockets iphone voip background
我的应用程序要求:出于某些原因,我应该维护套接字连接以在服务器推送时触发本地通知,而不使用推送通知(APN).所以我使用iPhone的VOIP后台功能来维护套接字连接.
1.我为VOIP配置了一个流,以便继续在后台运行套接字连接,那么我应该设置什么超时值?一旦超时到期,套接字连接是否会终止?如何使我的应用程序始终监听套接字.
客户端流配置如下,
NSString *urlStr = @"http://192.168.0.108";
NSURL *website = [NSURL URLWithString:urlStr];
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 1234, &readStream, &writeStream);
CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
NSInputStream *inputStream = (NSInputStream *)readStream;
NSOutputStream *outputStream = (NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ;
[outputStream setDelegate:self];
[outputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ;
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
Run Code Online (Sandbox Code Playgroud)
2.我应该在处理程序applicationDidEnterBackground中重新连接流:
[[UIApplication sharedApplication] setKeepAliveTimeout:86400 handler:^(void)
{
if (inputStream)
[inputStream close];
if (outputStream)
[outputStream close];
urlStr = @"http://192.168.0.108";
website = [NSURL URLWithString:urlStr];
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 1234, &readStream, &writeStream);
CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
inputStream = (NSInputStream *)readStream;
outputStream = (NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ;
[outputStream setDelegate:self];
[outputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ;
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}];
Run Code Online (Sandbox Code Playgroud)
3.说我的服务器重新启动,应用程序在后台,我该如何确保连接? 如果我的iPhone中的Wi-Fi连接或我终止服务器应用程序将关闭连接,那么我应该采取什么措施使我的应用程序按预期工作?
小智 19
您还需要确保已在pList文件中设置
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
</array>
Run Code Online (Sandbox Code Playgroud)
当您的应用程序在后台时,套接字将由iOS管理.只要插槽中有数据,您的应用程序就会收到CPU时间.所以在runLoop我正在检查ht
在我的情况下,信令协议在一个单独的线程中工作,所以我正在旋转runLoop我自己
// Start runloop
while (!m_needStop)
{
CFRunLoopRun();
}
Run Code Online (Sandbox Code Playgroud)
并在需要时停止它:
m_needStop = true;
{
QAutoLock l(m_runLoopGuard);
if ( m_runLoop != NULL )
CFRunLoopStop(m_runLoop);
}
Run Code Online (Sandbox Code Playgroud)
对于runLoop中的套接字,我在将它们安排到runLoop之前设置了处理函数:
int nFlags = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventCanAcceptBytes | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
CFStreamClientContext context;
context.info = this;
context.version = 0;
context.release = NULL;
context.retain = NULL;
context.copyDescription = NULL;
if ( !CFReadStreamSetClient(m_readStream, nFlags, NotificationProtocolHandler::ReadStreamCallback, &context) )
{
ReleaseStreams();
return false;
}
if ( !CFWriteStreamSetClient(m_writeStream, nFlags, NotificationProtocolHandler::WriteStreamCallback, &context) )
{
ReleaseStreams();
return false;
}
Run Code Online (Sandbox Code Playgroud)
这些函数将在您的套接字为您提供一些信息时调用,即使您的应用程序在后台运行:
void NotificationProtocolHandler::ReadStreamCallback(CFReadStreamRef stream,
CFStreamEventType eventType,
void *clientCallBackInfo)
{
NotificationProtocolHandler* handler = (NotificationProtocolHandler*)clientCallBackInfo;
switch (eventType)
{
case kCFStreamEventOpenCompleted:
break;
case kCFStreamEventHasBytesAvailable:
handler->ProcessInput();
break;
case kCFStreamEventErrorOccurred:
handler->ProcessConnectionError();
break;
case kCFStreamEventEndEncountered:
handler->ProcessConnectionError();
break;
default:
break; // do nothing
}
}
void NotificationProtocolHandler::WriteStreamCallback(CFWriteStreamRef stream,
CFStreamEventType eventType,
void *clientCallBackInfo)
{
NotificationProtocolHandler* handler = (NotificationProtocolHandler*)clientCallBackInfo;
switch (eventType)
{
case kCFStreamEventOpenCompleted:
handler->ProcessOutputConnect();
break;
case kCFStreamEventCanAcceptBytes:
handler->ProcessReadyToWrite();
break;
case kCFStreamEventErrorOccurred:
handler->ProcessConnectionError();
break;
case kCFStreamEventEndEncountered:
handler->ProcessConnectionError();
break;
default:
break; // do nothing
}
}
Run Code Online (Sandbox Code Playgroud)
为了使服务器知道客户端仍处于活动状态,我们每隔10分钟将ping命令发送到服务器,因此KeepAlive处理程序设置为600.您可以使用其他值来节省电池,但会检测到客户端上的断开连接会更糟糕和服务器端.并且会增加断开连接和重新连接之间的时间.
BOOL scheduled = [app setKeepAliveTimeout:pingTimeout handler:^{ // Schedule processing after some time interval
SchedulePing(0);
}
Run Code Online (Sandbox Code Playgroud)
SchedulePing(0)将执行如下:
StartLongBGTask();
if ( avoidFinishBgTask != NULL )
*avoidFinishBgTask = true;
m_pingTimer = CreateTimer(pingTimeout, PingTimerCallback); // result is ignored
Run Code Online (Sandbox Code Playgroud)
而StartLongBGTask是一个
m_bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{
[[UIApplication sharedApplication] endBackgroundTask:m_bgTask];
m_bgTask = UIBackgroundTaskInvalid;
}];
Run Code Online (Sandbox Code Playgroud)
这需要确保在发送ping并等待来自服务器的ping回复之前不会挂起应用程序.此外,如果套接字已经断开连接,则可能需要重新连接,这将花费一些时间并且需要proccess在后台运行.
但是,当您不再需要它们时,请务必正确释放后台任务.当超过bg超时时,系统将杀死其他明智的应用程序.
| 归档时间: |
|
| 查看次数: |
24785 次 |
| 最近记录: |