iOS上的VoIP套接字 – 未收到通知

我有一个VoIP应用程序,使用TCP服务在来电时唤醒它。 TCP套接字使用以下代码片段创build:

CFReadStreamRef read = NULL; CFWriteStreamRef write = NULL; ... CFStreamCreatePairWithSocketToHost(NULL,(__bridge CFStringRef)shost, port, &read, &write); self.read = (__bridge NSInputStream*)read; self.write = (__bridge NSOutputStream*)write; if (![self.read setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType]){ [Log log:@"Could not set VoIP mode to read stream"]; } if (![self.write setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType]){ [Log log:@"Could not set VoIP mode to write stream"]; } self.read.delegate = self; self.write.delegate = self; CFRelease(read); CFRelease(write); [self.read scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; [self.write scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; [self.read open]; [self.write open]; 

我还设置了以下内容:

  1. 信息plist中的VoIP和audio
  2. 使用[UIApplication sharedApplication] setKeepAliveTimeout保持活动计时器
  3. UIRequiresPersistentWiFi =是在信息plist(确定它不是必需的,但…)

当应用程序处于前台时,此function运行良好,甚至可以在后台运行几分钟,但几分钟后 – 应用程序不会收到任何新的TCP消息。 它不适用于WiFi或3G,两者的结果相同。

我也尝试设置只读属性的属性(虽然读写指向相同的套接字)。 每当我收到有关TCP的数据或发送数据,我也会开始一个简短的后台任务。 顺便说一句 – 一切都发生在主线上。
我检查了应用程序是否崩溃 – 事实并非如此。
在设备上debugging时可以观察到相同的行为 – 一段时间后,没有收到任何消息(没有崩溃,警告,任何东西)。

我究竟做错了什么?

看起来像你的代码应该工作。 但是我可以想到两个技术问题:

  1. 如果您尝试从局域网连接,而在后台的应用程序,而局域网路由器可以closures被动的TCP连接,因为在这种情况下,SIP堆栈(猜你使用SIP协议)不能发送数据保持活着每隔15到30秒在前景。

  2. 不太可能,假设你知道你在做什么,但是由于注册保持活跃状态​​只能在后台10分钟内触发一次,请确保SIP服务器允许这么长的过期,并且在注册消息中定义它。

尝试下面的代码。确保你的应用只有一个VoIPsockets。

 CFReadStreamRef readStream; CFWriteStreamRef writeStream; CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"1.2.3.4",9999, &readStream, &writeStream); CFReadStreamSetProperty(readStream,kCFStreamNetworkServiceType,kCFStreamNetworkServiceTypeVoIP); CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); inputStream = (NSInputStream *)readStream; [inputStream setDelegate:self]; [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [inputStream open]; outputStream = (NSOutputStream *)writeStream; [outputStream setDelegate:self]; [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [outputStream open]; 

ViewController.h文件中添加

 @property (nonatomic, strong) NSInputStream *inputStream; @property (nonatomic, strong) NSOutputStream *outputStream; @property (nonatomic) BOOL sentPing; 

ViewController.m文件中添加@implementation ViewController

 const uint8_t pingString[] = "ping\n"; const uint8_t pongString[] = "pong\n"; 

viewDidLoad添加以下代码

 CFReadStreamRef readStream; CFWriteStreamRef writeStream; CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)(@"192.168.0.104"), 10000, &readStream, &writeStream); //in above line user your MAC IP instead of 192.168.0.104 self.sentPing = NO; //self.communicationLog = [[NSMutableString alloc] init]; self.inputStream = (__bridge_transfer NSInputStream *)readStream; self.outputStream = (__bridge_transfer NSOutputStream *)writeStream; [self.inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType]; [self.inputStream setDelegate:self]; [self.outputStream setDelegate:self]; [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [self.inputStream open]; [self.outputStream open]; //After every 10 mins this block will be execute to ping server, so connection will be live for more 10 mins [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ if (self.outputStream) { [self.outputStream write:pingString maxLength:strlen((char*)pingString)]; //[self addEvent:@"Ping sent"]; } }]; - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { switch (eventCode) { case NSStreamEventNone: // do nothing. break; case NSStreamEventEndEncountered: //[self addEvent:@"Connection Closed"]; break; case NSStreamEventErrorOccurred: //[self addEvent:[NSString stringWithFormat:@"Had error: %@", aStream.streamError]]; break; case NSStreamEventHasBytesAvailable: if (aStream == self.inputStream) { uint8_t buffer[1024]; NSInteger bytesRead = [self.inputStream read:buffer maxLength:1024]; NSString *stringRead = [[NSString alloc] initWithBytes:buffer length:bytesRead encoding:NSUTF8StringEncoding]; stringRead = [stringRead stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; //[self addEvent:[NSString stringWithFormat:@"Received: %@", stringRead]]; //if server response is 'call' then a notification will go to notification center and it will be fired //immediately and it will popup if app is in background. if ([stringRead isEqualToString:@"call"]) { UILocalNotification *notification = [[UILocalNotification alloc] init]; notification.alertBody = @"New VOIP call"; notification.alertAction = @"Answer"; //[self addEvent:@"Notification sent"]; [[UIApplication sharedApplication] presentLocalNotificationNow:notification]; } //else if ([stringRead isEqualToString:@"ping"]) //{ //if server response is 'ping' then a sting 'pong' will go to server immediately //[self.outputStream write:pongString maxLength:strlen((char*)pongString)]; //} } break; case NSStreamEventHasSpaceAvailable: if (aStream == self.outputStream && !self.sentPing) { self.sentPing = YES; if (aStream == self.outputStream) { [self.outputStream write:pingString maxLength:strlen((char*)pingString)]; //[self addEvent:@"Ping sent"]; } } break; case NSStreamEventOpenCompleted: if (aStream == self.inputStream) { //[self addEvent:@"Connection Opened"]; } break; default: break; } } 

build立你的应用程序并运行

在你的MAC电脑上打开terminal,写入nc -l 10000 ,按回车

 $ nc -l 10000 

然后写call ,然后按回车