Установка потоков сокета
Можно использовать 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).
Протокол системы защиты с помощью цифровых сертификатов для обеспечения шифрования данных, аутентификации сервера, целостности сообщения и (дополнительно) аутентификации клиента для соединений TCP/IP.
Прокси-сервер SOCKS.
Сервер, находящийся между клиентским приложением и реальным сервером по соединению TCP/IP. Это прерывает запросы к реальному серверу и, если это не может выполнить их от кэша недавно требуемых файлов, вперед их к реальному серверу. Прокси-серверы SOCKS помогают улучшить производительность по сети и могут также использоваться для фильтрации запросов.
Для безопасности 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 ... |
} |
} |
Для получения дополнительной информации
Для узнавания больше об использовании потоков для сетей считайте Сетевой Обзор.