Per Apple的“轮询与运行循环调度”:
[
hasSpace/BytesAvailable
]可能意味着有可用的字节或空间或,找出的唯一方法是尝试读取或写入操作(这可能导致瞬间块)。
doc没有明确声明hasSpace / BytesAvailable 事件的行为方式相同,只是模糊地说它们具有“相同的语义”。
我是否可以得出结论,写入/读取streamError或字节读/写返回值小于预期量可能是由于“瞬间阻塞”?
如果是这样,我应该再次尝试传输吗?我应该使用某种计时器机制来阻止机会清除吗?这将是很多工作要实施,所以我宁愿不要,如果它不太可能帮助。
(在这种情况下启动一个有限的轮询循环很有吸引力,比如说10次尝试的while循环,但是我不知道在运行中调度流的同时执行此操作是否安全循环,我无法测试它。)
答案 0 :(得分:1)
这是套接字的好包装:https://github.com/robbiehanson/CocoaAsyncSocket
如果连接不可用,它将对读取进行排队。你没有提到你是使用UDP还是TCP,但是我怀疑你正在使用TCP,在这种情况下它会自己处理任何中断 - 只要连接没有被拆除。
答案 1 :(得分:1)
这是一个漫长的过程。以下是对此问题的一些跟进:
早期,我提出了维护和检查剩余缓存的想法,因为只有当进一步的反射表明输入流也会被阻塞时,这只会对输出流有效。
相反,我设置了空闲的while循环:
- (void) stream:(NSStream *)theStream handleEvent:(NSStreamEvent)eventCode {
switch (eventCode)
// RECEIVING
case NSStreamEventHasBytesAvailable: {
if (self.receiveStage == kNothingToReceive)
return;
// Get the data from the stream. (This method returns NO if bytesRead < 1.)
if (![self receiveDataViaStream:(NSInputStream *)theStream]) {
// If nothing was actually read, consider the stream to be idling.
self.bStreamIn_isIdling = YES;
// Repeatedly retry read, until (1) the read is successful, or (2) stopNetwork is called, which will clear the idler.
// (Just in case, add nil stream property as a loop breaker.)
while (self.bStreamIn_isIdling && self.streamIn) {
if ([self receiveDataViaStream:(NSInputStream *)theStream]) {
self.bStreamIn_isIdling = NO;
// The stream will have started up again; prepare for next event call.
[self assessTransmissionStage_uponReadSuccess];
}
}
}
else
// Prepare for what happens next.
[self assessTransmissionStage_uponReadSuccess];
break;
// SENDING
case NSStreamEventHasSpaceAvailable:
if (self.sendStage == kNothingToSend)
return;
if (![self sendDataViaStream:(NSOutputStream *)theStream]) {
self.bStreamOut_isIdling = YES;
while (self.bStreamOut_isIdling && self.streamOut) {
if ([self sendDataViaStream:(NSOutputStream *)theStream]) {
self.bStreamOut_isIdling = NO;
[self assessTransmissionStage_uponWriteSuccess];
}
}
}
else
[self assessTransmissionStage_uponWriteSuccess];
break;
// other event cases…
然后是时候通过“取消”按钮测试用户发起的取消。在同步的中途,Cocoa方面有一个暂停,等待用户输入。如果用户此时取消,Cocoa应用程序将关闭流并将其从runloop中删除,因此我预计连接的其他侧的流将生成NSStreamEventEndEncountered
个事件,或许NSStreamEventErrorOccurred
。但是,不,只有一个事件发生了,NSStreamEventHasBytesAvailable
!去图。
当然,实际上没有任何“字节可用”,因为流已经在Cocoa端关闭,而不是写入 - 所以iOS端的流处理程序进入无限循环。不太好。
接下来,我测试了其中一个设备进入睡眠状态会发生什么。在用户输入暂停期间,我让iPhone通过自动锁定*进入睡眠状态,然后在Cocoa端提供用户输入。再次惊喜:Cocoa应用程序继续没有扰动到同步结束,当我醒来iPhone时,iOS应用程序也证明已经完成了同步的一面。
我的闲置循环修复了iPhone方面的打嗝吗?我投入了一个停止网络例程来检查:
if (![self receiveDataViaStream:(NSInputStream *)theStream])
[self stopNetwork]; // closes the streams, etc.
同步仍然完成。没有打嗝。
最后,我测试了如果 Mac (Cocoa端)在暂停输入期间进入睡眠状态时发生了什么。这产生了一种向后冲击:在 Mac 侧收到了两个NSStreamEventErrorOccurred
事件,之后不再可能写入输出流。在iPhone方面没有收到任何事件,但如果我测试了iPhone的流状态,它将返回5,NSStreamStatusAtEnd。
结论&amp;计划:强>
NSStreamStatusAtEnd
和NSStreamStatusError
。但根据上述实验,这些表明断开连接。*如果它从属于Xcode,iPhone将无法入睡。你必须直接从iPhone上运行它。