Обнаружение ошибок подключения при использовании CFStreamCreatePairWithSocketToCFHost - PullRequest
1 голос
/ 23 ноября 2010

Я нахожу документ для CFStreamCreatePairWithSocketToCFHost сбивающий с толку:

В частности, мне не ясно, как функция может установить указатель readStream на ноль при ошибке. насколько я понимаю, указатель передается по значению - поэтому функция может изменять только объект, на который указывает указатель. Сейчас я не могу понять, как обнаружить ошибки подключения.

Соответствующий фрагмент документа:


Создает читаемые и записываемые потоки, связанные с данным объектом CFHost.

void CFStreamCreatePairWithSocketToCFHost (
   CFAllocatorRef alloc,
   CFHostRef host,
   SInt32 port,
   CFReadStreamRef *readStream,
   CFWriteStreamRef *writeStream
);

ReadStream

По возвращении содержит объект CFReadStream, подключенный к хосту хоста через порт, или NULL, если во время создания произошел сбой. Если вы передадите NULL, функция не создаст читаемый поток. Право собственности следует правилу создания.


Это мой код подключения, он идет вплоть до NSLog (@ "Connected"), даже когда сервер не работает.

NSLog(@"Attempting to (re)connect to %@:%d", m_host, m_port);
while(TRUE)
{
    CFHostRef host = CFHostCreateWithName(kCFAllocatorDefault, (CFStringRef)m_host);
    if (!host)
    {
        NSLog(@"Error resolving host %@", m_host);
        [NSThread sleepForTimeInterval:5.0];
        continue;
    }
    CFStreamCreatePairWithSocketToCFHost(kCFAllocatorDefault, host , m_port, &m_in, &m_out);
    CFRelease(host);

    if (!m_in)
    {
        NSLog(@"Error");
    }

    CFStreamClientContext context = {0, self,nil,nil,nil};

    if (CFReadStreamSetClient(m_in, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, networkReadEvent, &context))
    {
        CFReadStreamScheduleWithRunLoop(m_in, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
    }

    if (CFWriteStreamSetClient(m_out, kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, networkWriteEvent, &context))
    {
        CFWriteStreamScheduleWithRunLoop(m_out, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
    }


    BOOL success = CFReadStreamOpen(m_in);
    CFErrorRef error = CFReadStreamCopyError(m_in);
    if (!success || (error && CFErrorGetCode(error) != 0))
    {
        NSLog(@"Connect error %s : %d", CFErrorGetDomain(error), CFErrorGetCode(error));
        [NSThread sleepForTimeInterval:5.0];
    }
    else 
    {
        NSLog(@"Connected");
        break;
    }
}

Ответы [ 4 ]

1 голос
/ 25 января 2011

Из «Руководства по программированию CFNetwork»:

Открытие потока может быть длительным процессом, поэтому функции CFReadStreamOpen и CFWriteStreamOpen избегают блокировки, возвращая TRUE в указать, что процесс открытия потока начался. Проверять статус открытия, вызвать функции CFReadStreamGetStatus и CFWriteStreamGetStatus, который возвращает kCFStreamStatusOpening, если открыт все еще выполняется, kCFStreamStatusOpen, если открытие завершено, orkCFStreamStatusErrorOccourced, если открытие завершилось, но не удалось. В большинстве случаев не имеет значения, завершено ли открытие, потому что функции CFStream, которые читают и пишут, будут блокироваться до тех пор, пока поток открыт.

Также проверьте kCFStreamEventOpenCompleted , (http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFStreamConstants/Reference/reference.html) : потоковое событие, которое сообщает об успешном завершении открытия процесс. Итак, чтобы завершить, после вызова CFReadStreamOpen (или Write), что, вероятно, удастся, зарегистрируйтесь, чтобы прослушать "OpenCompleted" событие для выявления «реального» успеха.

1 голос
/ 23 ноября 2010

Конечно, после того, как вы позвоните CFStreamCreatePairWithSocketToCFHost(), просто проверьте readstream, чтобы увидеть, если это NULL?

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

Редактировать

Я попробовал ваш код, и я согласен, это очень запутанно. Похоже, что CFReadStreamRef легко создается и открывается даже для бессмысленного хоста (я буквально использовал «ерунду»). Я не верю, что эта функция будет возвращать указатели NULL для недоступного хоста.

Я полагаю, что это имеет смысл, поскольку до тех пор, пока кто-то не попытается открыть поток, будет он работать или нет, неизвестно.

0 голосов
/ 23 января 2011

В документации для CFReadStreamOpen мы видим:

Открытие потока заставляет его резервировать все необходимые системные ресурсы. Если поток может открываться в фоновом режиме без блокировки, эта функция всегда возвращает true.

Я подозреваю, что поток открывается в фоновом режиме, и поэтому вы говорите "Подключен", прежде чем он действительно открывается. Вы уже запланировали поток с помощью цикла запуска, поэтому если вы позволите циклу выполнения выполняться, вы, вероятно, получите обратный вызов с типом события, установленным на kCFStreamEventErrorOccurred, и оттуда вы можете обработать ошибку соответствующим образом.

0 голосов
/ 23 января 2011

Таким образом, параметр readStream является указателем на CFReadStreamRef и, как таковой, может определенно быть установлен в NULL функцией. & foo означает «адрес foo», и если у вас есть адрес, вы можете установить значение.

Мое чтение документации для CFStreamCreatePairWithSocketToCFHost заключается в том, что при сбое им будет присвоено значение NULL, но этот сбой связан не со сбоем соединения, а с другими видами сбоя (память и т. Д.). Так что вряд ли вы получите там ошибку.

Похоже, проблема в том, что CFReadStreamOpen может немедленно вернуться с true, когда он может открыть поток в фоновом режиме, и поэтому этот код не открывает поток или не проверяет, что он был открыт, а просто ставит его в очередь на открытие). Из документации для CFReadStreamOpen:

"Если поток может открываться в фоновом режиме без блокировки, эта функция всегда возвращает true."

Так что я думаю, что вам нужно будет следовать остальным инструкциям для CFReadStreamOpen и планировать поток в цикле выполнения или, возможно, в опросе (хотя очевидно, что опрос в тесном цикле вряд ли будет работать).

...