我有一个VoIP应用程序,它使用TCP服务在来电时唤醒它。 使用以下代码片段创建TCP套接字:
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];
我还设置了以下内容:
这在应用程序处于前台时运行良好,甚至在后台运行良好几分钟,但几分钟后 - 该应用程序不会收到任何新的TCP消息。 它不适用于wifi或3G,两者都有相同的结果。
我还尝试将属性设置为读取流(尽管读取和写入指向同一个套接字)。
每当我收到TCP上的数据或发送数据时,我也会开始一个简短的后台任务。
顺便说一句 - 一切都发生在主线上
我检查了应用程序是否崩溃 - 它没有。
在设备上进行调试时可以观察到相同的行为 - 一段时间后 - 没有收到任何信息(没有崩溃,警告,任何事情)。
我做错了什么?
答案 0 :(得分:3)
请尝试以下代码。确保您的应用中只有一个voip套接字。
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];
答案 1 :(得分:3)
看起来您的代码应该有效。但我可能会想到两个技术问题:
如果从局域网连接尝试此操作,而在后台应用程序中局域网路由器可以关闭被动TCP连接,因为在这种情况下,SIP堆栈(猜测你使用SIP协议)无法每15个发送数据保持活动状态
不太可能,假设您知道自己在做什么,但由于注册保持活动只能在10分钟内触发,而在后台运行,请确保SIP服务器允许这么长的过期时间并且您可以在注册信息。
答案 2 :(得分:0)
在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;
}
}
构建您的应用并运行
在MAC PC中打开终端并写下nc -l 10000
并按Enter键
$ nc -l 10000
然后写下call
并按Enter键