ios - Keep Alive 在 iOS 上无法正常工作

标签 ios swift xcode alamofire nsurlsession

我目前正在开发一个应用程序,我们需要一些请求尽快访问我们的服务器。为了加快请求过程,我们必须消除握手(因为它需要额外的时间)并建立永久连接。

应用程序使用 Alamofire 框架向我们的服务器发出所有请求,设置如下:

我们有一个使用默认配置和 http header 设置的 session 管理器。

lazy var sessionManager: Alamofire.SessionManager = {
    let configuration = URLSessionConfiguration.default
    configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
    let manager = Alamofire.SessionManager(configuration: configuration)
    return manager
}()

session 管理器在所有请求中都是持久的。每个请求都使用以下代码发出:

self.sessionManager.request(request.urlString, method: request.method, parameters: request.parameters)
            .responseJSON { [weak self] response in
    // Handle the response
}

request.urlString 是我们服务器的 url "http://ourserver.com/example "

request.method 设置为post

request.parameters 是一个参数字典

请求工作正常,我们得到了有效的响应。 问题出现在保持事件计时器上,我们的服务器将其设置为 300 秒。该设备在 wifi 上保持连接最多 30 秒,并在通过 GSM 时几乎立即关闭。


服务器调试

我们在我们的服务器上做了一些调试,发现了以下结果

测试:

测试 1:

  • iPhone 通过 WiFi 连接到互联网

测试 2:

  • iPhone 通过 3G 连接到互联网

行为:

  • 两种情况:应用通过“Connection: keep-alive”向网络服务器发出 HTTP/1.1 请求;服务器(服务器 ip = 10.217.81.131)响应“Keep-Alive:timeout=300,max=99”
  • 客户端(测试 1 - WiFi 上的应用)在第 30 秒发送 TCP FIN 并关闭连接
  • 客户端(测试 2 – 3G 上的应用程序)在从其第一个 HTTP POST 接收到 HTTP/1.1 OK 消息后立即(零秒)发送 TCP FIN 请求

服务器端测试1日志:

  1. 在 23.101902,应用程序使用“Connection: keep-alive”向服务器发出 HTTP/1.1 POST 请求 enter image description here

  2. 在 23.139422 处,服务器响应 HTTP/1.1 200 OK 并显示“Connection: Keep-Alive”和“timeout=300”(300 秒) enter image description here

  3. 报告的往返时间 (RTT) 为 333.82 毫秒(这突出显示了我们在以下时间戳上的误差范围):

enter image description here

  1. 然而,该应用程序会在 30 秒内关闭连接(考虑到互联网传输方式的变化——54.200863 和 23.451979 时间戳之间的差异): enter image description here

  2. 该测试以大约 1 次重复多次。 30秒时间一直被监控

在服务器端测试2条日志:

  1. 来自应用的 HTTP/1.1 POST 请求: enter image description here
  2. 接受 keep-alive 的 HTTP OK 服务器响应并将其设置为 300 秒: enter image description here
  3. RTT 为 859.849 毫秒 enter image description here

应用程序立即关闭连接,立即为 21.197918 – 18.747780 = 2.450138 秒

在从 WiFi 切换到 3G 并返回时重复测试,并记录相同的结果。

客户端调试

使用 WiFi

第一次尝试(已建立连接)

Optional(
[AnyHashable("Content-Type"): text/html,

AnyHashable("Content-Encoding"): gzip, 

AnyHashable("Content-Length"): 36, 

AnyHashable("Set-Cookie"): user_cookieuser_session=HXQuslXgivCRKd%2BJ6bkg5D%2B0pWhCAWkUPedUEGyZQ8%2Fl65UeFcsgebkF4tqZQYzVgp2gWgAQ3DwJA5dbXUCz4%2FnxIhUTVlTShIsUMeeK6Ej8YMlB11DAewHmkp%2Bd3Nr7hJFFQlld%2BD8Q2M46OMRGJ7joOzmvH3tXgQtRqR9gS2K1IpsdGupJ3DZ1AWBP5HwS41yqZraYsBtRrFnpGgK0CH9JrnsHhRmYpD40NmlZQ6DWtDt%2B8p6eg9jF0xE6k0Es4Q%2FNiAx9S9PkhII7CKPuBYfFi1Ijd7ILaCH5TXV3vipz0TmlADktC1OARPTYSwygN2r6bEsX15Un5WUhc2caCeuXnmd6xy8sbjVUDn72KELWzdmDTl6p5fRapHzFEfGEEg2LOEuwybmf2Nt6DHB6o6EA5vfJovh2obpp4HkIeAQ%3D; expires=Sun, 08-Jan-2017 12:51:43 GMT; path=/,

AnyHashable("Keep-Alive"): timeout=300, max=100, 

AnyHashable("Connection"): Keep-Alive, 

AnyHashable("X-Powered-By"): PHP/5.3.10-1ubuntu3.11, 

AnyHashable("Server"): Apache/2.2.22 (Ubuntu), 

AnyHashable("Vary"): Accept-Encoding, 

AnyHashable("Date"): Sun, 08 Jan 2017 10:51:43 GMT])

第二次尝试(30 秒内,连接仍然有效)

Optional([AnyHashable("Content-Type"): text/html, 

AnyHashable("Content-Encoding"): gzip, 

AnyHashable("Content-Length"): 36, 

AnyHashable("Keep-Alive"): timeout=300, max=99, 

AnyHashable("Connection"): Keep-Alive, 

AnyHashable("X-Powered-By"): PHP/5.3.10-1ubuntu3.11, 

AnyHashable("Server"): Apache/2.2.22 (Ubuntu), 

AnyHashable("Vary"): Accept-Encoding, 

AnyHashable("Date"): Sun, 08 Jan 2017 11:00:18 GMT])

然后 30 秒后连接断开 (FI)

使用 3G

第一次尝试

Optional([AnyHashable("Content-Type"): text/html, 

AnyHashable("Content-Encoding"): gzip, 

AnyHashable("Content-Length"): 36, 

AnyHashable("Connection"): keep-alive, 

AnyHashable("X-Powered-By"): PHP/5.3.10-1ubuntu3.11, 

AnyHashable("Server"): Apache/2.2.22 (Ubuntu), 

AnyHashable("Vary"): Accept-Encoding, 

AnyHashable("Date"): Sun, 08 Jan 2017 11:04:31 GMT])

然后连接几乎立即断开。

最佳答案

现在我又看了一遍代码,我想我明白了问题所在。底层 NSURLSession 类默认忽略 keep-alive header ,因为一些服务器“支持”它,但实际上,如果你真的尝试使用它,会严重破坏,IIRC .

如果您希望 session 支持保持事件状态,则必须在 session 配置中显式地将HTTPShouldUsePipelining 设置为YES

请注意,仍然无法保证连接会保持畅通,这取决于 iOS 决定对 radio 进行电源管理的积极程度,但至少你会祈祷。 :-)

关于ios - Keep Alive 在 iOS 上无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41482187/

相关文章:

c++ - Xcode 5 项目在模拟器 3.5 上运行,但在设备上出现链接器错误

iphone - 如何在 iPhone 上缩放图像并保持按钮大小相同,类似于 Facebook 应用程序图像查看器?

swift - 从 swift 访问 api 网关端点时出现 "unsupported URL"错误

ios - 如何在我的 LaunchStoryboard 中显示 CFBundleShortVersionString?

ios - 如何将旧版本的 iOS SDK 复制到新版本的 Xcode?

ios - 在 Xcode 中切换运行脚本构建阶段

ios - 当我有多个资源时如何使用 ADAL 库

ios - 无法从 iOS 访问 https 网络服务

ios - Xcode 存档上传失败,出现错误

ios - 如何在 Swift 中访问其类之外的类型变量?