Objective c 使用CFStreamCreatePairWithSocketToCFHost时检测连接错误

Objective c 使用CFStreamCreatePairWithSocketToCFHost时检测连接错误,objective-c,core-foundation,Objective C,Core Foundation,我发现该文件令人困惑: 具体来说,我不清楚函数如何在出错时将readStream指针设置为null。 据我所知,指针是通过值传递的——因此函数只能更改指针指向的对象。 现在我不知道如何检测连接错误 相关文档片段: 创建连接到给定CFHost对象的可读写流 void CFStreamCreatePairWithSocketToCFHost ( CFAllocatorRef alloc, CFHostRef host, SInt32 port, CFReadStreamRe

我发现该文件令人困惑:

具体来说,我不清楚函数如何在出错时将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;
    }
}

当然,在调用
CFStreamCreatePairWithSocketToCFHost()
之后,只需测试
readstream
,看看它是否为
NULL

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

编辑

我已经试过你的代码了,我同意,它非常混乱。看起来,
CFReadStreamRef
很容易创建和打开,即使对于无意义主机也是如此(我字面上使用了“无意义”)。我不相信这个函数会为无法访问的主机返回空指针


我认为这是有意义的,因为在尝试打开流之前,它是否工作是未知的。

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

我对CFStreamCreatePairWithSocketToCFHost文档的理解是,它们在出现故障时将被设置为NULL,但该故障与连接故障无关,而是与其他类型的故障(内存等)有关。所以你不太可能在那里出错

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

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

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

在我们的文档中看到:

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

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

来自“CFNetwork编程指南”:

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

还可以查看kCFStreamEventOpenCompleted, () :报告打开成功完成的流事件 过程总之,在调用CFReadStreamOpen(或Write)之后, 哪一个可能会成功,请注册收听“OpenCompleted” 确定“真正”成功的事件


函数签名采用指针,而不是指针引用(或指向指针的指针)。函数签名为
CFReadStreamRef*readStream
。不要忘记,
CFReadStreamRef
已经是一个指针,因为它相当于
NSInputStream*
。好的,很好。但是-我尝试在服务器关闭时连接到服务器,并且readstream在调用后不为null(即使它们在输入中为nil)。您可以发布您正在执行的代码吗?可能更容易准确地看到发生了什么。在调用函数之前,是否将
m_in
m_out
显式设置为NULL?那可能会解决你的问题。实际上我已经在做了。