Problems understanding cURL multi-interface

BlitzMax Forums/Brucey's Modules/Problems understanding cURL multi-interface

jtfrench(Posted 2008) [#1]
Hey folks,

So I've been using the BlitzMax/cURL mod that Brucey put up, and it's been awesome. I've been working on a multiplayer game, and its awesome being able to deal with the less time-sensitive data transfers over simple HTTP as opposed to doing a low-level socket transfer.

I'm having trouble getting getting cURL to operate asynchronously by using the multi-interface, and I believe my problem stems from not understanding how to use the multiSelect() command.

Currently what I do is

a) create my multihandle
b) prepare my individual easy handles
c) call multiPerform() on the multihandle
d) check the return value of multiPerform(), as well as monitor how many running connections are in the variable it takes as an argument

No where do I use multiSelect(), mainly because I don't see why I should have to if multiPerform() can tell me if there is more data to be retrieved.

What I've noticed though is that it is possible for multiPerform(running) to return CURLM_OK event though running > 0. This perplexed me because it looks like cURL finished processing the HTTP requests, yet still has pending operations lingering.

Looking at the sample code, I notice they suggest the following usage:



I don't understand the usage of multiSelect(), and the documentation doesn't give much details on what exactly its purpose is, or how necessary it is. Additionally, I don't get why we perform several while loops on the same multi handle in order to complete *one* multi request. My understanding that you call multiPerform() as many times as you need until you get CURLM_OK, apparently that's not the case.

Can someone help me out with this?

Thanks,

Jason


Brucey(Posted 2008) [#2]
"select" simply indicates that a file is ready - or not... which implies that it is busy still. "select" allows you to test the file state without blocking.
"multiPerform" returns the current state of the connection, and whether or not it is ready for/with more data. Again this is non-blocking.

The idea is that you can call these in a normal loop, not have to worry about your app coming to a halt while you wait for files/connections, and therefore gain background file transfers, which otherwise you'd have to do manually.

This API is a bit crazy though. I do see there's a slightly less exciting version which simplifies things a bit. I'll have a look and see if I can get it implemented at some point.


jtfrench(Posted 2008) [#3]
So I think I understand that select() lets you know when the file stream is ready, but if so, then why do you loop on multiPerform() prior to that? It appears to me like the sample code does the following:

1) Calls the initial multiPerform() request

2) Checks that status, and if CURLM_CALL_MULTI_PERFORM, it keeps doing it until it changes to CURLM_OK

3) Use multiSelect() to determine if stream ready

4) if ready, we repeat steps 1) and 2)

I'm just confused why we (loop) call multiPerform() the first time, then do a multiSelect(), then do it all over again? what's the point of the first time we loop on multiPerform() versus the second time?

I hope that makes sense!

-jason


jtfrench(Posted 2008) [#4]
Anyone has any insight to offer ?

:)


Brucey(Posted 2008) [#5]
what's the point of the first time we loop on multiPerform() versus the second time?

The multiPerform() return status indicates whether it is ready to accept new data, or if it is busy transferring it. Once it returns OK, then it requires more data, so we check if the file/stream is ready by calling multiSelect(). If that is ready, then we can safely call multiPerform again.

Why? Well, both functions are non-blocking... *if* things are in the correct state. If you were to attempt to read from a file that wasn't ready, the read would block, and your app would pause momentarily. By querying these in this order, you guarantee that the process of transferring a file/stream won't block, and therefore your app should run smoothly.

I believe there's a newer method to accomplish this task now, which I should have a look at at some point, which is a little less "technical" to use :-)