On 04/02/2011 17:39, Mike wrote:
> 1. The debug info is suggesting that if a connection is used, it is
> set to expire in 20 seconds (in my case -- 60 by ASI default). And
> then if that connection is reused within that 20 seconds, the expiry
> is reset back to 20. Is this how persistent connections are meant to
> work? Would a connection remain open for an hour provided there are
> requests constantly using it? Or does the remote server close it?
>
It could be possible for the connection to stay open for an hour I
believe, if you're making requests at least every 20 seconds.
Are you thinking this could be an issue?
Some servers will close the connection before that - eg. Apache has a
MaxRequestsPerChild, which defaults to 10,000 in the current builds I
believe, but was lower in older versions and can be configured by the
server admin. The time the server will allow the connection to remain
idle is also configurable.
> 2. Is there a maximum number of connections setting? I can't find
> one. The internet suggests that a client should only maintain two
> connections with the server but I'm not sure this is being honoured.
>
I use this:
[[ASIHTTPRequest sharedQueue] setMaxConcurrentOperationCount:2];
If you're not using the shared queue, or are using multiple queues,
you'll need to modify that.
Joseph
> I've been having problems with persistent connections
I fear you're not the only one - I can't think of another ASIHTTPRequest feature that's caused more confusion... :)
>> 1. The debug info is suggesting that if a connection is used, it is
>> set to expire in 20 seconds (in my case -- 60 by ASI default). And
>> then if that connection is reused within that 20 seconds, the expiry
>> is reset back to 20. Is this how persistent connections are meant to
>> work? Would a connection remain open for an hour provided there are
>> requests constantly using it? Or does the remote server close it?
>>
> It could be possible for the connection to stay open for an hour I believe, if you're making requests at least every 20 seconds.
I think it would depend on how the server implements persistent connections, but broadly speaking, yes.
The behaviour of persistent connections seems to vary widely between servers. Apache has a sensible system for handling persistent connections, which primarily involves two things:
* The number of times a connection can be reused for a request (defaults to 100)
* The number of seconds a connection will stay open for while idle (defaults to 5)
Apache is helpful enough to send clients this information in the Keep-Alive header (I think nginx does this too). This means that ASIHTTPRequest can adapt its behaviour according to what the server tells it to do with the connection.
Unfortunately, Keep-Alive is not part of the HTTP standard, so many web servers don't send it. The HTTP RFC has information on how clients should handle a closed connection (http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html), but unfortunately CFNetwork does not expose the underlying connections used by HTTP requests in the public APIs, so ASIHTTPRequest can't always deal with this in a sensible fashion. If ASIHTTPRequest encounters a stream error that looks like a closed connection, it will attempt to retry the request on a new connection. This doesn't always work though, as with some servers you just get timeouts.
>> 2. Is there a maximum number of connections setting? I can't find
>> one. The internet suggests that a client should only maintain two
>> connections with the server but I'm not sure this is being honoured.
>>
> I use this:
>
> [[ASIHTTPRequest sharedQueue] setMaxConcurrentOperationCount:2];
>
> If you're not using the shared queue, or are using multiple queues, you'll need to modify that.
Just to clarify on Joseph's suggestion - the sharedQueue is used for all requests started with startAsynchronous.
For anyone else finding this, the tricks for persistent connections are:
1) If you can configure your server to send a keep-alive header, do so. This should solve 99% of all problems.
2) If not, try to find out how the server handles timing out connections. If it manages them on the basis of the number of seconds idle, set persistentConnectionTimeoutSeconds accordingly, and you should see much more reliable behaviour. If this doesn't seem to be documented for your server, you can usually make an educated guess based on the output from DEBUG_PERSISTENT_CONNECTIONS, as Matt has done.
3) Disable persistent connections for requests with a body (eg POST or PUT)
4) If all else fails, disable persistent connections.
I think I will add this to the documentation. :)
Best,
Ben
First of all, those are great answers and info. Thanks to both of
you. I have one question about the tricks that Ben mentioned.
> For anyone else finding this, the tricks for persistent connections are:
>
> 1) If you can configure your server to send a keep-alive header, do so. This should solve 99% of all problems.
> 2) If not, try to find out how the server handles timing out connections. If it manages them on the basis of the number of seconds idle, set persistentConnectionTimeoutSeconds accordingly, and you should see much more reliable behaviour. If this doesn't seem to be documented for your server, you can usually make an educated guess based on the output from DEBUG_PERSISTENT_CONNECTIONS, as Matt has done.
> 3) Disable persistent connections for requests with a body (eg POST or PUT)
> 4) If all else fails, disable persistent connections.
I've ended up going with trick #3/#4 for now because it's working, but
I'm curious why you recommend this for POST/PUT. Does your
recommendation hold even if the body is very small?
Just in case there's interest: My problem is similar to what you would
see if the server says Keep-Alive is 20 seconds but is actually
closing connections at 10 or so seconds. ASIHttpRequest tries to use
a connection well within the 20 second boundary (at about the 12 or 13
second mark) but it fails. This might very well be the server's fault
and until I can setup my own test server and get more info, I'm going
to drop the issue. Debug output suggests ASI is doing the right
thing.
Thanks again for the connection info.
Mike