Связь с клиентами на основе TCP не работает в iOS 11?

У меня есть приложение IoT, которое использует Socket Programming для связи с устройством. Все хорошо до выхода iOS 11. Он не взаимодействует в iOS 11 и выше, но работает в более ранних версиях (до 10). Вот код.

Установление соединения сокетов

(void)setUpSocketConnection {
    @try {
        CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef) VeranoHost,VeranoPort , &readStream, &writeStream);
        [self open];
    }
    @catch (NSException *exception) {
        NSLog(@"Open Exception:%@", exception.reason);
    }   
}

Открытие потоков

(void)open {
    //NSLog(@"Opening streams.");
    _outputStream = (__bridge  NSOutputStream *)writeStream;
    _inputStream = (__bridge  NSInputStream *)readStream;
    [_outputStream setDelegate:self];
    [_inputStream setDelegate:self];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
    dispatch_async(queue, ^ {
            [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [[NSRunLoop currentRunLoop] run];
    });

    [_outputStream open];
    [_inputStream open];

    //[self disableNaglesAlgorithmForStream:_inputStream];
   // NSLog(@"Connected");
//    self.timeOutTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
//                                                         target:self
//                                                       selector:@selector(timerTimeOutAction:)
//                                                       userInfo:nil
//                                                        repeats:NO];
}

Запись в выходной поток

(void)writeData:(NSString *)message forSocketType:(SOCKETTTYPE)socketType {
    self.socketType = socketType;
    NSData *data = [[NSData alloc] initWithData:[message dataUsingEncoding:NSASCIIStringEncoding]];
    [_outputStream write:[data bytes] maxLength:[data length]];
    [_outputStream close];

}

Обработчик событий

(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
   // NSLog(@"stream event %lu", (unsigned long)streamEvent);
    switch (streamEvent) {
        case NSStreamEventOpenCompleted:{

           // NSLog(@"NSStreamEventOpenCompleted :::: Stream opened and connected");
        }
            break;
        case NSStreamEventHasBytesAvailable:
            // NSLog(@"NSStreamEventHasBytesAvailable :::: Stream opened and connected");
            if (theStream == _inputStream) {
                uint8_t buffer[1024];
                NSInteger len;

                while ([_inputStream hasBytesAvailable])
                {
                    len = [_inputStream read:buffer maxLength:sizeof(buffer)];
                    if (len > 0)
                    {
                        NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];

                        if (nil != output)
                        {
                            NSLog(@"server said: %@", output);
                            [self messageReceived:output];
                        }
                    }
                }
            }
            break;
        case NSStreamEventHasSpaceAvailable:
           // NSLog(@"NSStreamEventHasSpaceAvailable :::: Stream has space available now");
            break;

        case NSStreamEventErrorOccurred:{
           NSError *theError = [theStream streamError];
            NSLog(@"Error Description:%@",theError.localizedDescription);
            [self close];
            if(self.delegate &&[self.delegate respondsToSelector:@selector(socketHandlerItem:failureWithError:forSocketType:)]){
                [self.delegate socketHandlerItem:self failureWithError:[theStream streamError] forSocketType:self.socketType];
            }
             //NSLog(@"NSStreamEventErrorOccurred :::: %@",[theStream streamError].localizedDescription);
        }
            break;

        case NSStreamEventEndEncountered:
            [theStream close];
            [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            if(self.delegate &&[self.delegate respondsToSelector:@selector(socketHandlerItem:eventStopedWithstatus:forSocketType:)]){
                [self.delegate socketHandlerItem:self eventStopedWithstatus:YES forSocketType:self.socketType];
            }
           // NSLog(@"NSStreamEventEndEncountered :::: close stream Disconnected");
            break;
        default:
           // NSLog(@"Unknown event");
            break;
    }
}

Таким образом, при подключении к сокету он переходит к NSStreamEventErrorOccurred в обработчике событий и журналах - The operation couldn’t be completed. No route to host

Любая помощь будет принята с благодарностью.

Обновление от 19 декабря 2017 года

  • Получил Reachability оболочку, которая позволяет обнаружить адрес хоста, и я могу подтвердить, что он возвращает NetworkStatus ReachableViaWiFi
  • Связь сокетов работает нормально, я попытался создать образец серверного сокета, способного отправлять и получать данные.

Обновление 20 декабря 2017 г. (1)

Подробное описание устройства IoT - USR-WIFI232-S Модуль беспроводной сети с низким энергопотреблением

Руководство пользователя Здесь

Обновление 20 декабря 2017 г. (2)

Eurekaa, но решение не может применяться в режиме реального времени. При настройке ближайшего диапазона статического IP-адреса в iOS 11, соответствующем адресу хоста модуля IoT, связь работает нормально. но он не работает с динамически распределенным IP-адресом.

Ответы

Ответ 1

Я удивляюсь, если это безопасность транспорта приложений (ATS), см. https://www.nowsecure.com/blog/2017/08/31/security-analysts-guide-nsapptransportsecurity-nsallowsarbitraryloads-app-transport-security-ats-exceptions/

Для iOS 11 ATS обновляется некоторое количество обновлений ATS как часть этого:

  • TLSv1.3 получит предварительную поддержку
  • 3DES будет удален из утвержденного списка шифров.
  • Сертификаты, подписанные с SHA1, больше не будут приниматься
  • Сертификаты, подписанные с ключами RSA, должны иметь длину в 2048 бит или больше

PLIST и права, которые вы используете в своем приложении?

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSExceptionDomains</key>
    <dict>

        <key>creativecommons.org</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
            <false/>
        </dict>

        <key>localhost</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>

    </dict>
</dict>

Также еще один вариант, если вы хотите отключить ATS, вы можете использовать это:

<key>NSAppTransportSecurity</key>  
 <dict>  
      <key>NSAllowsArbitraryLoads</key><true/>  
 </dict>

Но это не рекомендуется!