我发现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;
}
}
答案 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>