iOS NSStream FTP在5分钟不活动后没有响应

时间:2014-12-04 20:07:31

标签: ios ftp nsstream

我正在使用iOS的FTP库(nkreipke/FTPManager)。它很棒。我可以下载目录列表,上传图像等。 问题是如果你让应用程序打开5分钟,什么都不做,然后你尝试下载或上传,没有任何反应。

我一直在调试它,发现NSStreamDelegate方法 - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent 永远不会在那个短暂的不活动的时间。

以下是代码:

- (NSArray*) _contentsOfServer:(FMServer*)server {
BOOL success = YES;

action = _FMCurrentActionContentsOfServer;

fileSize = 0;

self.directoryListingData = [[NSMutableData alloc] init];

NSURL* dest = [server.destination ftpURLForPort:server.port];
And(success, (dest != nil));
Check(success);

if (![dest.absoluteString hasSuffix:@"/"]) {
    //if the url does not end with an '/' the method fails.
    //no problem, we can fix this.
    dest = [NSURL URLWithString:[NSString stringWithFormat:@"%@/",dest.absoluteString]];
}

CFReadStreamRef readStream = CFReadStreamCreateWithFTPURL(NULL, (__bridge CFURLRef)dest);
And(success, (readStream != NULL));
if (!success) return nil;
self.serverReadStream = (__bridge_transfer NSInputStream*) readStream;

And(success, [self.serverReadStream setProperty:server.username forKey:(id)kCFStreamPropertyFTPUserName]);
And(success, [self.serverReadStream setProperty:server.password forKey:(id)kCFStreamPropertyFTPPassword]);
if (!success) return nil;

self.bufferOffset = 0;
self.bufferLimit = 0;

currentRunLoop = CFRunLoopGetCurrent();

self.serverReadStream.delegate = self;
[self.serverReadStream open];
[self.serverReadStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

CFRunLoopRun(); //<- Hangs here.

And(success, streamSuccess);
if (!success) return nil;

NSArray* directoryContents = [self _createListingArrayFromDirectoryListingData:self.directoryListingData];
self.directoryListingData = nil;

return directoryContents;

serverReadStream是 NSInputStream 对象。

当行动结束时:

if (self.serverReadStream) {
    [self.serverReadStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.serverReadStream.delegate = nil;
    [self.serverReadStream close];
    self.serverReadStream = nil;
}

此代码位于 FTPManager.m 。我一直在寻找互联网上的答案,但无法找到任何答案。我不知道为什么NSStreamDelegate方法在经常使用时会被调用,但是在一段时间不活动之后,它就不会被调用。

如果有人可以帮助我,那就太好了。

感谢。

1 个答案:

答案 0 :(得分:1)

我在我的iPad应用程序中使用相同的库,当我在恢复应用程序时尝试刷新FTP服务器内容时,我被困在同一个CFRunLoopRun()调用中。

我必须对FTPManager代码进行两处更改。

首先,我改变了

的顺序
[self.serverReadStream open];
[self.serverReadStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[self.serverReadStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.serverReadStream open];

原因是流不能打开。在打开调用期间引发错误事件,但如果流未调度到运行循环,我们将永远不会收到错误事件。因此,在打开之前安排将允许我们获取错误事件。

我的案例中需要的另一个更改是禁用持久连接。似乎在设备的挂起/恢复周期之后,流使用的内部套接字会变得很小,并且在尝试访问它时总是返回错误。

在流配置中添加以下行已经解决了我的问题:

[self.serverReadStream setProperty: (id) kCFBooleanFalse forKey: (id) kCFStreamPropertyFTPAttemptPersistentConnection];

希望这有帮助。