使用CFStreamCreatePairWithSocketToCFHost时检测连接错误

时间:2010-11-23 12:50:57

标签: objective-c core-foundation

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

具体来说,我不清楚函数如何在出错时将readStream指针设置为null。 据我所知,指针是通过值传递的 - 所以函数只能改变指针指向的对象。 现在我无法弄清楚如何检测连接错误。

相关文档摘要:


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

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

readStream

返回时,包含连接到端口端口上的主机主机的CFReadStream对象,如果在创建期间出现故障,则为NULL 。如果传递NULL,则该函数不会创建可读流。所有权遵循创建规则。


这是我的连接代码,即使服务器关闭,它也会一直到NSLog(@“已连接”)。

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 个答案:

答案 0 :(得分:1)

当您致电CFStreamCreatePairWithSocketToCFHost()后,只需测试readstream,看看它是NULL吗?

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

修改

我已经尝试过您的代码了,我同意,这非常令人困惑。似乎CFReadStreamRef很容易创建和打开,即使对于无意义的主机(我实际上使用“废话”)。我不相信这个函数会为无法访问的主机返回NULL指针。

我认为这是有道理的,直到有人试图打开流,无论它是否有效都是未知的。

答案 1 :(得分:1)

来自“CFNetwork编程指南”:

  

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

     

同时查看 kCFStreamEventOpenCompleted ,   (http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFStreamConstants/Reference/reference.html)   :报告成功完成开放的流事件   处理。总而言之,在调用CFReadStreamOpen(或Write)之后,   这可能会成功,注册听“OpenCompleted”   确定“真正”成功的事件。

答案 2 :(得分:0)

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

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

在我看来,问题是CFReadStreamOpen可以立即返回true,因为它可以在后台打开流,所以这段代码并没有真正打开流或测试它已被打开,只是排队等待打开)。来自CFReadStreamOpen的文档:

“如果流可以在后台打开而不会阻塞,则此函数始终返回true。”

所以我认为你需要遵循CFReadStreamOpen的其余指令并在运行循环上调度流,或者轮询(尽管显然在紧密循环中轮询不太可能有效)。

答案 3 :(得分:0)

CFReadStreamOpen的文档中,我们看到:

  

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

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