Установка потоков сокета

Можно использовать API CFStream для установления сокетного соединения и, с потоковым объектом (или объекты) создаваемый в результате отправляют данные в и получают данные от удаленного узла. Можно также сконфигурировать соединение для безопасности.

Основная процедура

Класс NSStream не поддерживает соединение с удаленным узлом на iOS. CFStream действительно поддерживает это поведение, однако, и как только Вы создали свои потоки с API CFStream, можно использовать в своих интересах бесплатный мост между CFStream и NSStream для кастинга CFStreams к NSStreams. Просто вызовите CFStreamCreatePairWithSocketToHost функция, обеспечивая имя хоста и номер порта, для получения обоих a CFReadStreamRef и a CFWriteStreamRef для данного узла. Можно тогда бросить эти объекты в NSInputStream и NSOutputStream и продолжиться.

Перечисление 1 иллюстрирует использование CFStreamCreatePairWithSocketToHost. Этот пример показывает создание обоих a CFReadStreamRef объект и a CFWriteStreamRef объект. Если Вы хотите получить только один из этих объектов, просто укажите NULL как значение параметра для нежелательного объекта.

Перечисление 1  , Настраивающее сетевой поток сокета

- (IBAction)searchForSite:(id)sender
{
    NSString *urlStr = [sender stringValue];
    if (![urlStr isEqualToString:@""]) {
        NSURL *website = [NSURL URLWithString:urlStr];
        if (!website) {
            NSLog(@"%@ is not a valid URL");
            return;
        }
 
        CFReadStreamRef readStream;
        CFWriteStreamRef writeStream;
        CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 80, &readStream, &writeStream);
 
        NSInputStream *inputStream = (__bridge_transfer NSInputStream *)readStream;
        NSOutputStream *outputStream = (__bridge_transfer NSOutputStream *)writeStream;
        [inputStream setDelegate:self];
        [outputStream setDelegate:self];
        [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [inputStream open];
        [outputStream open];
 
        /* Store a reference to the input and output streams so that
           they don't go away.... */
        ...
    }
}

Если Вы передаете в недопустимых параметрах, один или оба из требуемых CFReadStreamRef и CFWriteStreamRef объекты NULL. Как только Вы бросили CFStreams к NSStreams, установили делегата, планируете поток на цикл выполнения и открываете поток, как обычно. Делегат должен начать получать потоковые сообщения о событиях (stream:handleEvent:). Посмотрите Чтение От Входных Потоков и Запись В Потоки вывода для получения дополнительной информации.

Обеспечение и конфигурирование соединения

Перед открытием потокового объекта Вы могли бы хотеть установить безопасность и другие функции соединения с удаленным узлом (который мог бы быть, например, сервером HTTPS). NSStream определяет свойства, влияющие на безопасность сокетных соединений TCP/IP двумя способами:

Для безопасности SSL, NSStream определяет различные свойства уровня безопасности (например, NSStreamSocketSecurityLevelSSLv2). Вы устанавливаете эти свойства путем отправки setProperty:forKey: к потоковому объекту с помощью ключа NSStreamSocketSecurityLevelKey, как в этом демонстрационном сообщении:

[inputStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey];

Необходимо установить свойство перед открытием потока. Как только это открывается, это проходит через протокол квитирования для обнаружения, какой уровень безопасности SSL другая сторона соединения использует. Если уровень безопасности не совместим с указанным свойством, потоковый объект генерирует ошибочное событие. Однако, если Вы запрашиваете согласованный уровень безопасности (NSStreamSocketSecurityLevelNegotiatedSSL), уровень безопасности становится самым высоким, которое могут реализовать обе стороны соединения. Однако, при попытке установить уровень безопасности SSL, когда удаленный узел не безопасен, ошибка сгенерирована.

Для конфигурирования прокси-сервера SOCKS для соединения необходимо создать словарь с ключами формы NSStreamSOCKSProxyИмяKey (например, NSStreamSOCKSProxyHostKey). Значение каждого ключа является определением прокси SOCKS, к которому относится Имя. Тогда использование setProperty:forKey:, установите словарь как значение NSStreamSOCKSProxyConfigurationKey.

Инициирование запроса HTTP

Если Вы открываете соединение с сервером HTTP (т.е. веб-сайт), то Вам, вероятно, придется инициировать транзакцию с тем сервером путем отправки ему Запроса HTTP. Хорошее время для подачи с этим запросом когда делегат NSOutputStream объект получает a NSStreamEventHasSpaceAvailable событие через a stream:handleEvent: сообщение. Перечисление 2 показывает делегату, создающему HTTP-запрос GET и пишущему его в поток вывода, после которого это сразу закрывает потоковый объект.

Перечисление 2  , Делающее HTTP-запрос GET

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
    NSLog(@"stream:handleEvent: is invoked...");
 
    switch(eventCode) {
        case NSStreamEventHasSpaceAvailable:
        {
            if (stream == oStream) {
                NSString * str = [NSString stringWithFormat:
                    @"GET / HTTP/1.0\r\n\r\n"];
                const uint8_t * rawstring =
                    (const uint8_t *)[str UTF8String];
                [oStream write:rawstring maxLength:strlen(rawstring)];
                [oStream close];
            }
            break;
        }
        // continued ...
    }
}

Для получения дополнительной информации

Для узнавания больше об использовании потоков для сетей считайте Сетевой Обзор.