【问题标题】:Detecting connection errors when using CFStreamCreatePairWithSocketToCFHost使用 CFStreamCreatePairWithSocketToCFHost 时检测连接错误
【发布时间】:2017-10-23 22:08:36
【问题描述】:

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

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

相关文档sn-p:


创建连接到给定 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;
    }
}

【问题讨论】:

  • 在调用函数之前,您是否明确将m_inm_out 设置为NULL?这可能会解决您的问题。
  • 其实我已经在做这个了。

标签: objective-c core-foundation


【解决方案1】:

来自“CFNetwork 编程指南”:

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

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

【讨论】:

    【解决方案2】:

    在你打电话给CFStreamCreatePairWithSocketToCFHost() 之后,一定要测试readstream 看看是不是NULL

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

    编辑

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

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

    【讨论】:

    • 函数签名采用指针,而不是指针的引用(或指向指针的指针)
    • 函数签名是CFReadStreamRef *readStream。不要忘记CFReadStreamRef 已经是一个指针,因为它等价于NSInputStream *
    • 好的,好点。但是 - 我尝试在服务器关闭时连接到服务器,并且调用后读取流不为空(即使它们在输入中为零)。
    • 你能发布你正在执行的代码吗?可能更容易准确地看到正在发生的事情。
    【解决方案3】:

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

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

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

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

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

    【讨论】:

      【解决方案4】:

      CFReadStreamOpen 的文档中,我们看到:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-16
        • 1970-01-01
        • 2021-07-01
        • 2014-03-02
        • 1970-01-01
        • 1970-01-01
        • 2014-07-03
        相关资源
        最近更新 更多