您的位置:首页 > 理论基础 > 计算机网络

ASIHTTPRequest Understanding persistent connection reuse

2012-02-13 16:19 351 查看
转自:http://groups.google.com/group/asihttprequest/browse_thread/thread/49f58c66f00d993a/ce14ee901960e92a

问:

Hey all,

Either I see a problem in the ASI stuff, or am not understanding how

persistent connections are supposed to work in it. Either way...

I've integrated a031a030f949 into my codebase (was HEAD not too long

ago if it isn't still) in order to add Keep-Alive support to my

project. I'm still in the "get it back to where it was before

upgrading" stage, so I haven't done any work to get Keep-Alives

working.

I use the NSOperation method of doing requests. I create a request

(sometimes ASIHTTPRequest, sometimes ASIFormDataRequest) every time I

want to do a new transaction.

The behavior I'm seeing is that at the start of the app, the

connections all work. After that, none of them work. They all have an

error as follows:

2010-03-08 10:00:59.977 MyApp[47253:207] RESTHelper[0x54207f0]: Error

was Error Domain=ASIHTTPRequestErrorDomain Code=1 UserInfo=0x5413a80

"A connection failure occurred"

2010-03-08 10:01:00.018 MyApp[47253:207] RESTHelper[0x54207f0]: Error

userInfo is {

NSLocalizedDescription = "A connection failure occurred";

NSUnderlyingError = Error Domain=NSPOSIXErrorDomain Code=57

UserInfo=0x1293800 "Operation could not be completed. Socket is not

connected";

}

So.. how *should* I be creating the connections? Keeping a pool of my

own to reuse? That seems in keeping with the

ASIHTTPRequest#connectionCanBeReused property. I notice that each

ASIHTTPRequest has its own connection pool, and I don't understand why

that would be, since it's an instance variable, not global.

Any help you can offer would be immensely appreciated. :)

Jimmy

答:

Hi Jimmy

> Either I see a problem in the ASI stuff, or am not understanding how

> persistent connections are supposed to work in it. Either way...

As you've discovered, the way persistent connections work is rather confusing. :) This is mostly because the way they work in CFNetwork is very confusing (and, as far as I can see, entirely undocumented, except for
a few Apple mailing list posts...)

ASIHTTPRequest has a connection pool, stored in the static array persistentConnectionsPool. Each item in this pool is actually a dictionary that contains:

* information about the host, port and scheme (eg http) the connection is for

* a reference to the request that is currently using a connection (if there is one)

* a reference to the stream used for the request

* an ID that uniquely identifies the connection

* a date corresponding with when the connection should expire

When a request is started, it first looks in the connection pool to see if there is a connection it can reuse. It will attempt to reuse a connection if:

* The host, port and scheme are the same as the request

* The date the connection is supposed to expire has not yet passed

* The connection is not already in use (if it has a value for the request key, it is already in use)

If it finds a connection to use, the request will set its connectionInfo property to the dictionary for the connection it will use. If not, it creates a new connectionInfo dictionary (since it will need to create a new
connection) and adds it to the pool. If it finds any connections that should have expired, it removes them from the pool.

Behind the scenes, CFNetwork keeps connections open as long as there is a stream attached to that connection that hasn't been closed. So, when a request finishes, we actually keep the readStream open so a subsequent request
can use the connection - once a new request starts and its stream has been opened, we close the old stream.

Each connection's unique ID is used to 'tag' the readStream to tell CFNetwork 'reuse the connection that matches this id, or create a new connection if you can't find a connection that matches this id'. As far as I know,
there is no way to access to the actual connection itself - all you can do is to provide CFNetwork with a hint as to your intention.


-
显示引用的文字 -

Each request has its own connectionInfo dictionary, and the pool (which is global for all ASIHTTPRequests) is an array of these connectionInfo dictionaries.

You shouldn't really need to do anything special to make persistent connections work. connectionCanBeReused is really only used internally - it has a public accessor so I can see what a request is doing in tests. The
only property you should generally need to worry about is shouldAttemptPersistentConnection - if you set this to NO, ASIHTTPRequests won't attempt to use persistent connections at all.

The first step in debugging problems with persistent connections should be to turn on DEBUG_PERSISTENT_CONNECTIONS (the easiest way is to modify ASIHTTPRequestConfig.h). This will cause ASIHTTPRequest to print information
about how it is using and reusing connections to the console.

Also, check the headers the server you are connecting to returns. If it returns a Keep-Alive header, ASIHTTPRequest can use the information about when the connection should expire to prevent the kind of problem you've
been seeing (I'm guessing, it is trying to use connections that should have been closed). If it isn't returning a keep-alive header, ASIHTTPRequest will attempt to reuse the connection for 60 seconds after the request using it finishes. Depending on the server
you're connecting to, this may be the wrong number entirely - servers tuned for performance may well close unused connections much earlier.

I think the main flaw in the current implementation is ASIHTTPRequest won't attempt to retry if the server closes the connection - I hope to look at this fairly soon.

I hope this makes sense!

Best

Ben
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: