英文:
iOS and Go - Keep-Alive using NSURLSession
问题
在我的iOS应用中,我有一个搜索功能,从服务器获取结果。当用户更新查询时,搜索实时更新,这导致连续进行多个请求。
所以我的问题是,如何确保这些连接使用TCP keep-alive?我希望尽量减少延迟,所以重要的是在第一个请求之后保持连接,并在后续请求中重复使用。
我正在使用NSURLSession,并且听说它默认使用keep-alive,但我怎么确定呢?在服务器上记录请求时,每个连续的请求之间没有任何区别,但我不希望仅仅从头信息中看到任何变化。
有什么帮助吗?我在服务器上使用Go语言,所以可能需要在那一侧进行一些额外的配置。
英文:
In my iOS app, I have a search feature that fetches results from a server. The search updates live as the user updates their query, so this results in several requests being made in succession.
So my question is, how can I ensure that TCP keep-alive is being used on these connections? I'd like to reduce as much latency as possible, so it's important that a connection be maintained after the first request and reused for the following requests.
I'm using NSURLSession, and I've heard that it employs keep-alive by default, but how can I know for sure? Logging the requests on the server show no difference between each successive request, but I wouldn't expect to see any change just from the header information.
Any help here? I'm using Go on my server, so it's possible that it needs some additional configuration on that side too.
答案1
得分: 12
我相信你把TCP keep-alive和HTTP keep-alive(持久连接)搞混了。这两个概念是不相关的。根据你的问题,你可能指的是HTTP持久连接。
在HTTP/1.1中,持久连接是默认的,并且被NSURLSession
和几乎所有的HTTP/1.1客户端使用。你需要主动关闭它们。你可以检查HTTP头中的Connection: close
,或者在服务器端检查http.Request
的Close
字段。但我确定你正在使用持久连接。这意味着你不需要为每个请求重新协商TLS隧道(或至少进行TCP三次握手)。(尽管如果你发起并行请求,仍然会有多个连接需要协商。HTTP/1.1一次只能处理一件事情,而NSURLSession
会尝试使用连接池来提高响应时间。)
TCP keep-alive是完全不同的东西。它会定期发送一个“ping”到另一端,以确保它仍然可达。有很多情况下你可能会失去网络连接,而在下一次尝试通信之前你可能都不会知道,正常的症状就是连接卡住,你需要设置超时时间。理论上,TCP keep-alive就是用来发现这个问题的工具,但我几乎从未发现它实用。它很难正确配置(尤其在Cocoa中)。你几乎总是需要为你的应用程序构建一个更高级的“ping”功能,而不是依赖于它。
但是回到你的问题,对于你来说,HTTP/1.1可能已经足够了,但你需要仔细管理你的响应。如果你为每个字母都发起一个新的请求并返回一个庞大的响应,那么效果会很差。你会让连接池忙于下载你将要丢弃的东西。你首先需要关注好的算法。至少,你可能只想一次发送几个结果,并在你的API中提供“分页”方法来请求更多与同一搜索相关的结果。
英文:
I believe you're confusing TCP keep-alive with HTTP keep-alive (persistent connections). These are unrelated concepts. From your question, you probably mean HTTP persistent connections.
In HTTP/1.1, persistent connections are the default and are used by NSURLSession
and nearly every HTTP/1.1 client. You have to ask to turn them off. You can check for a Connection: close
in the HTTP header, or on the server side, you can check the Close
field of the http.Request
. But I'm sure you're getting persistent connections. This means that you don't have to renegotiate the TLS tunnel (or at a minimum the TCP three-way handshake) for every request. (Though if you make parallel requests, there will still be multiple connections that you have to negotiate. HTTP/1.1 can only handle one thing at a time, and NSURLSession
will try to use a pool of connections to improve response times.)
TCP keep-alives are a completely different thing. It sends a periodic "ping" to the other side to make sure it's still reachable. There are many ways for you to lose network connectivity and not know it until the next time you try to communicate, and the normal symptom is that the connection just hangs and you need to time it out. In theory TCP keep-alive is just the tool for discovering this, but I have almost never found it practical. It's difficult to configure properly (especially in Cocoa). You will almost always need to build a higher-level "ping" functionality for your application rather than relying on this.
But bringing it around to your problem, HTTP/1.1 is probably fine for you as-is, but you're going to need to carefully manage your responses. If you make a new request for every letter and send back a massive response, then that's going to work badly. You're going to keep all your connection pool busy downloading things that you're going to throw away. You need to focus first on good algorithms. At a minimum, you probably only want to send a few results at a time and provide a "paging" approach in your API to ask for more results for the same search.
答案2
得分: 7
要确切了解TCP的工作情况,您可以启用CFNETWORK_DIAGNOSTICS。根据文档:
> 在正常开发过程中,您可以通过Xcode的方案编辑器设置此环境变量。如果您需要在Xcode之外调查问题,可以使用列表1中显示的代码以编程方式设置它。
>
> 列表1:以编程方式启用CFNetwork诊断日志记录
>
setenv("CFNETWORK_DIAGNOSTICS", "3", 1);
>
> 您应该在应用程序启动序列的开始处执行此操作。通常将其放在main函数的开头就足够了,但如果您有使用CFNetwork的C++静态初始化程序,您需要在它们之前运行它。
>
> 当您首次使用CFNetwork或任何使用CFNetwork的框架(如Foundation)时,CFNetwork诊断日志记录将启动,此时它将打印类似列表2中显示的消息。
>
> 列表2:CFNetwork诊断日志记录启动消息示例
>
2014-10-28 14:23:37.115 QTestbed[2626:60b] CFNetwork diagnostics log file created at: /private/var/mobile/Applications/76531F40-3291-4565-8C75-0438052C83BC/Library/Logs/CrashReporter/CFNetwork_com.example.apple-samplecode.QTestbed_2626.nwlrb
英文:
To know for sure what TCP is doing, you can enable CFNETWORK_DIAGNOSTICS. From the docs:
> During normal development you can set this environment variable via Xcode's scheme editor. If you need to investigate problems outside of Xcode, you can set it programmatically using the code shown in Listing 1.
>
>Listing 1 Programmatically enabling CFNetwork diagnostic logging
>
setenv("CFNETWORK_DIAGNOSTICS", "3", 1);
>
>You should do this right at the beginning of the app's launch sequence. Normally putting this at the start of main is sufficient, but if you have C++ static initialisers that use CFNetwork you'll have to run it before them.
>
>CFNetwork diagnostic logging starts up when you first use CFNetwork—or any framework, like Foundation, that uses CFNetwork—at which point it will print a message like that shown in Listing 2.
>
>Listing 2 An example of the CFNetwork diagnostic logging startup message
>
2014-10-28 14:23:37.115 QTestbed[2626:60b] CFNetwork diagnostics log file created at: /private/var/mobile/Applications/76531F40-3291-4565-8C75-0438052C83BC/Library/Logs/CrashReporter/CFNetwork_com.example.apple-samplecode.QTestbed_2626.nwlrb
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论