1

我发现CFStreamCreatePairWithSocketToCFHost的文档令人困惑:

具体来说,我不清楚该函数如何在错误时将 readStream 指针设置为 null。据我了解,指针是按值传递的——所以函数只能改变指针指向的对象。现在我不知道如何检测连接错误。

相关文档片段:


创建连接到给定 CFHost 对象的可读和可写流。

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

读流

返回时,包含连接到端口端口上的主机主机的 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

4 回答 4

1

当然,在你打电话后CFStreamCreatePairWithSocketToCFHost()只是测试readstream看看它是NULL不是?

当您传入 readstream 指针的内存位置时,该函数可以轻松地将其设置为它选择的任何值(对已创建对象的引用,或者 NULL)。

编辑

我试过你的代码,我同意,这很混乱。似乎CFReadStreamRef很容易创建和打开,即使对于废话主机(我字面上使用“废话”)。我不相信这个函数会为无法访问的主机返回 NULL 指针。

我认为这是有道理的,就在尝试打开流之前,它是否会起作用是未知的。

于 2010-11-23T13:14:08.163 回答
1

来自“CFNetwork 编程指南”:

打开流可能是一个漫长的过程,因此 CFReadStreamOpen 和 CFWriteStreamOpen 函数通过返回 TRUE 来指示打开流的过程已经开始来避免阻塞。要检查打开的状态,调用函数 CFReadStreamGetStatus 和 CFWriteStreamGetStatus,如果打开仍在进行中,则返回 kCFStreamStatusOpening,如果打开已完成,则返回 kCFStreamStatusOpen,如果打开已完成但失败,则返回 kCFStreamStatusErrorOccurred。在大多数情况下,打开是否完成并不重要,因为读取和写入的 CFStream 函数会阻塞,直到流打开。

另请查看kCFStreamEventOpenCompletedhttp://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFStreamConstants/Reference/reference.html):报告打开过程成功完成的流事件。总而言之,在调用可能会成功的 CFReadStreamOpen(或 Write)之后,注册以侦听“OpenCompleted”事件以识别“真正的”成功。

于 2011-01-25T09:53:40.090 回答
0

因此,readStream 参数是指向 CFReadStreamRef 的指针,因此,函数绝对可以将其设置为 NULL。&foo 表示“foo 的地址”,如果你有地址,你可以设置值。

我对 CFStreamCreatePairWithSocketToCFHost 文档的阅读是,它们将在失败时设置为 NULL,但该失败不是连接失败,而是其他类型的失败(内存等)。所以不太可能你会在那里得到一个错误。

在我看来,问题是当 CFReadStreamOpen 可以在后台打开流时,它可以立即返回 true,因此这段代码并没有真正打开流或测试它是否已打开,只是将其排队等待打开)。从 CFReadStreamOpen 的文档中:

“如果流可以在后台打开而不阻塞,这个函数总是返回true。”

因此,我认为您将需要遵循 CFReadStreamOpen 的其余说明并将流安排在运行循环上,或者可能是轮询(尽管显然在紧密循环中轮询不太可能起作用)。

于 2011-01-22T21:12:02.837 回答
0

CFReadStreamOpen的文档中,我们看到:

打开流会导致它保留所需的所有系统资源。如果流可以在后台打开而不会阻塞,则此函数始终返回 true。

我怀疑流正在后台打开,因此您在实际打开之前说“已连接”。您已经使用 runloop 安排了流,因此如果您让 run loop 运行,您可能会收到一个事件类型设置为 的回调kCFStreamEventErrorOccurred,然后您可以从那里适当地处理错误。

于 2011-01-23T02:04:29.493 回答