NSURLConnection在大约5分钟后忽略服务器响应–无超时



我遇到了NSURLConnection的问题,我现在有一段时间无法解决。

我向服务器发出请求,但处理数据需要很长时间(平均约7分钟)。因此,客户端需要等待响应,因此我试图通过在NSURLRequest中设置长时间超时来保持HTTP连接的打开状态。我不希望在这个时候采用基于民意调查的解决方案。

请求代码:

- (void)sendNextExample
{
    url = ...
    json = ...
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                                                           cachePolicy:NSURLRequestReloadIgnoringCacheData
                                                       timeoutInterval:600.0];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:json];
    NSURLConnection *newConnection = [[NSURLConnection alloc] initWithRequest:request
                                                                     delegate:self
                                                             startImmediately:NO];
    if (!queue)
    {
        queue = [NSOperationQueue new];
    }
    [newConnection setDelegateQueue:queue];
    self.connectionStatus = @{@"index" : @(i), @"data" : [NSMutableData data]};
    [newConnection start];
}

处理代码(简化):

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSMutableData *buffer = self.connectionStatus[@"data"];
    [buffer appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    // log and interrupt process
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // do sth with buffer data
    // finalize
}

问题是,我从未从服务器接收到任何信息,并且连接超时(600秒=10分钟后,如NSURLRequest中所定义),即使该过程似乎在服务器端完成。在连接超时之前,任何时候都不会调用任何委托方法


为了验证服务器处理并将数据正确返回给客户端,我通过使用curl:从完全相同的客户端向完全相同的服务器执行几个请求进行了测试

curl -H "Content-Type: application/json" -X POST -d '{"foo":0.0, "bar":1.0}' serveraddress:8000

这些请求似乎按预期工作,即上述请求在7分钟后返回正确的数据:

{"bar":0.5, "baz":10.0} // expected data

因此,我怀疑罪魁祸首在于NSURLConnection,所有其他事情都是一样的。

作为下一步,我使用不同持续时间的服务器端进程执行了几个请求,并发现NSURLConnection在请求后大约5分钟后开始忽略响应。


那么问题自然是,有人经历过这种情况吗?这种行为看起来正常/意料之中吗

即使在请求中正确设置了超时,NSURLConnection在一定时间后会忽略接收到的数据,这是否有任何原因(甚至可能是操作系统介导的)?任何可能导致这种情况的精细打印或未记录的"功能"

最终,切换到NSURLConnection以外的东西,比如AFNetworking,会让我有机会绕过这个明显的"限制"吗?

(当然,如果有任何关于如何以另一种方式执行任务的建议,也非常欢迎!)


为了清楚起见,客户端是Yosemite机器(Xcode 7),服务器是使用.Net 4.5(Windows 8机器)中的HttpListener编写的。该服务器已在其他场合进行了测试,并按预期工作。


编辑:这个问题发布半年多后,问题仍然存在。我成功地完成了我的工作,用可可调用curl(不优雅,但有效),因此无数次验证了罪魁祸首确实在NSURLConnection中。我最后得出结论,这是一个bug,我会发布它(如果我有时间的话),但说实话,我并没有太大希望。

EDIT2:轮询显然是另一种选择。但是,我不能使用轮询,因为我的一些请求需要非常快地返回(<<1秒),而其他请求需要很长时间(>1分钟)。使用轮询意味着增加请求/响应所需的最短时间。

如果NSURLConnection失败,NSURLSession和基于它的一切都有可能失败,所以不,AFNetworking不应该有任何区别。

我很好奇为什么要为每个请求创建一个单独的NSOperationQueue实例。这相当浪费资源;NSURLConnection本质上是异步的,所以它不会阻塞操作队列,除非它正在运行回调代码。很少有理由使用您自己的操作队列,除非您的委托方法出于某种原因必须执行一些重大任务。

无论哪种方式,即使使用curl(如果你真的需要链接到libcurl,而不是运行一个单独的进程,你可能只需要链接到它),这种设计仍然存在根本问题,因为一旦你的网络很差,你就会在服务器处理完你的请求之前很久就超时。此外,如果连接似乎不再使用,一些基于NAT的防火墙可能会忘记映射,此时您的请求将永远无法完成。

最好将方法更改为上传数据,服务器为您提供一个URL,您可以在其中检查进度,您的客户端请求该URL,然后服务器提供状态。然后,您的客户端可以每隔一段时间重新检查状态,最终发出一个请求,检索处理后的数据并删除服务器上的文件。

如果你不介意让一个线程在你的web服务器中运行,你也可以使用MIME多部分响应,这样当你询问该状态URL的内容时,web服务器每n秒就会发回一个新的状态blob,但这是否是个好主意取决于你的服务器体系结构。

最新更新