Сохранение соединения сокета в iOS
У меня есть следующий код, написанный в Objective-C, который записывает данные в сокет. Сервер работает node.js поверх Ubuntu:
NSString *url = @"anIPAddress";
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)url, 9000, &readStream, &writeStream);
self.inputStream = (NSInputStream *)readStream;
self.outputStream = (NSOutputStream *)writeStream;
[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];
Я могу подключиться к серверу и отправить информацию. Однако я заметил, что соединение истекает через несколько минут (я думаю, 5 минут или около того?). Как я могу сохранить это соединение в живых? Я знаю, что есть разъединение, потому что то же самое происходит, если я подключаюсь к серверу под терминалом, я должен сохранить это соединение в живых. Я предполагаю, что то же самое происходит в моем коде. Спасибо за вашу помощь!
Ответы
Ответ 1
Я нашел, как это сделать. Поскольку сервер работает node.js, я использовал
socket.setKeepAlive(true, 2000);
И таким образом node сохраняет каждый сокет открытым. Значение по умолчанию - false, поэтому именно поэтому время было отключено. Надеюсь, это полезно другим людям. Спасибо за ваши ответы, я думаю, что сохранение сердечного ритма (keep-alive) также является хорошей идеей, но с этим родным подходом node позаботится об этом.
Ответ 2
Самый простой ответ - попытаться использовать опцию сокета SO_KEEPALIVE
.
Сломанные соединения могут быть трудно обнаружить без передачи данных между конечными точками, что делает эту опцию в некотором смысле бесполезной, поскольку она не использует данные для обнаружения сломанных соединений. Однако его легко добавить к вашему коду. Добавьте его и посмотрите, поможет ли он...
Вот как это делается на C или С++
int opt = 1;
// Get the native socket handle from your socket class here...
int socket_handle = getNativeSocketHandle( self.outputStream );
/*Enabling keep alive*/
if( setsockopt( socket_handle, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof( opt ) ) < 0 )
{
// failed setting socket option
}
Непростой ответ заключается в добавлении пакета ping
в ваш протокол и отправке этого пакета ping регулярно, чтобы вы могли обнаружить неисправное соединение.
Ответ 3
Вам необходимо регулярно отправлять мусор через соединение. Попробуйте следующее:
NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:240 target:self selector:@selector(timerMethod:) userInfo:[NSNumber numberWithInt:sockfd] repeats:YES];
Затем объявите это в self
:
-(void)timerMethod:(NSTimer*)t
{
send([[t userInfo] intValue], "Keepalive!", 11, 0);
}
Примечание. Замените "Keepalive!". с тем, что вы хотите для своего протокола. Единственным требованием является то, что удаленный конец (сервер сокетов) игнорирует сообщение.
Ответ 4
Предполагая NSOutputStream * oStream;
В iOS сделайте это так:
#if 1 // Using CF
CFDataRef data = (CFDataRef)CFWriteStreamCopyProperty((__bridge CFWriteStreamRef)oStream, kCFStreamPropertySocketNativeHandle);
if(data) {
CFSocketNativeHandle socket_handle = *(CFSocketNativeHandle *)CFDataGetBytePtr(data);
CFRelease(data);
#else // Using Foundation
NSData *data = (NSData *)[oStream propertyForKey:(__bridge NSString *)kCFStreamPropertySocketNativeHandle];
if(data) {
CFSocketNativeHandle socket_handle = *(CFSocketNativeHandle *)[data bytes];
#endif
NSLog(@"SOCK HANDLE: %x", socket_handle);
/*Enabling keep alive*/
if( setsockopt( socket_handle, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof( opt ) ) < 0 )
{
NSLog(@"Yikes 2: failed to set keepalive! ERRNO: %s", strerror(errno));
}
Я публикую это, так как я просто потратил часы на все это, хочу сохранить кого-то еще.