iOS和Go-使用NSURLSession保持活动

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.

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.

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