【问题标题】:NSURLConnection ignoring server response after ~5 mins – no timeoutNSURLConnection 在约 5 分钟后忽略服务器响应——没有超时
【发布时间】:2016-03-23 06:04:45
【问题描述】:

我遇到了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。我终于得出结论,这是一个错误,并将发布它(如果我有时间这样做),但老实说,我并没有抱太大希望。

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

【问题讨论】:

    标签: objective-c cocoa http timeout nsurlconnection


    【解决方案1】:

    如果 NSURLConnection 失败,那么 NSURLSession 和所有基于它的东西很可能也会失败,所以不,AFNetworking 应该没有任何区别。

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

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

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

    如果您不介意在 Web 服务器中保留线程,您还可以使用 MIME 多部分响应,这样当您请求该状态 URL 的内容时,Web 服务器会在每个 n 秒,但这是否是一个好主意取决于您的服务器架构。

    【讨论】:

    • 不幸的是,我不能按照您的建议使用轮询,因为有些请求需要快速返回(
    • 你处理这种情况的方式基本上还是一样的,只是A.你应该在初始上传请求之后立即发出轮询请求,B.当服务器收到轮询请求时,它应该等待响应,直到资源实际准备好。当然,操作系统有时会在一段时间后断开连接,此时您的应用应立即重试轮询请求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-12
    • 2018-03-29
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 2019-12-12
    相关资源
    最近更新 更多