Связь с клиентами на основе 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>
Но это не рекомендуется!