cURL / Mailing Lists / curl-library / Single Mail

curl-library

Multiple connects to the same HTTP(S) server

From: Nimrod A. Abing <nimrod.abing_at_gmail.com>
Date: Mon, 20 Feb 2006 02:42:07 +0800

Hello,

I am writing an application that requires more than one connection to
the same HTTP server and I am using the curl_multi_* interface. I am
aware that maintaining more than two connections to the HTTP server is
against the RFC but this is a requirement for the app I am writing.

Here is what happens during execution of my app:

1. App starts a queue for curl handle objects, with a continuous loop
that checks if there are curl handle objects waiting. If there are,
then a function that calls curl_multi_perform is called.

2. User selects a file for upload via GUI.

3. A curl handle is initialized and created for the request (series of
form_add()'s).

4. Curl handle is passed to a queue of curl handle objects. The queue
automatically adds the handle via curl_multi_add_handle() afer the
handle is added to the queue itself.

Now this setup seems to work fine in most cases. I am able to do
several uploads at once as long as *none* of those transfers take a
lot of time to finish. The problem is that if an upload is waiting for
a response from the server, other uploads/downloads seem to be
blocked. I don't know much about curl internals but I thought
curl_multi_perform() is *not* supposed to block even though one of
those transfers is waiting for a response from the server.

The server I am connecting to takes some time to respond after an
upload is finished since it has to do post processing on the uploaded
file (e.g. validation, compression, encryption). When it is done with
those steps, only then will it send a response to the client.

I am able to reproduce the problem consistently. First I upload a file
and wait for it to be uploaded, it will cause the server to take some
time to respond. Then I try to do a second upload or even just a
"server ping" (which is just an HTTP request to a special URL on the
server). The app will then hang up seemingly waiting for the first
request to finish with a reply from the server.

I have tried even using threads with this, running the queue in a
separate thread. Initially I tried multithreaded easy handles with
curl_easy_perform. Same results, which is why I swiched to the
multiplexing interface. I even have the following setopt calls for
each new handle I create:

curl_easy_setopt(handle, CURLOPT_FORBID_REUSE, TRUE);
curl_easy_setopt(handle, CURLOPT_FRESH_CONNECT, TRUE);

To make sure that none of the new connection requests will be waiting
on a stale connection. Nothing seems to work. The following is the
body of the function where curl_multi_perform is called from the queue
processing loop:

        while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(cm,
&ongoingTransfers));

        if (0 != ongoingTransfers) {
                struct timeval timeout;
                int rc, maxfd;
                fd_set fdread, fdwrite, fdexcep;

                FD_ZERO(&fdread);
                FD_ZERO(&fdwrite);
                FD_ZERO(&fdexcep);

                timeout.tv_sec = 0;
                timeout.tv_usec = 0;

                curl_multi_fdset(cm, &fdread, &fdwrite, &fdexcep, &maxfd);

                rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);

                switch (rc) {
                        case -1:
                                wxLogDebug(wxT("select() returned with
error."));
                                break;

                        case 0:
                                wxLogDebug(wxT("select() returned
after timeout."));
                                break;

                        default:
                                wxLogDebug(wxT("select() returned %d
connections ready for R/W."), rc);
                                break;
                }
        }

        int remaining = 0;
        CURLMsg* msg;
        if (NULL != (msg = curl_multi_info_read(cm, &remaining))) {
                curl_multi_remove_handle(cm, msg->easy_handle);
                queue->RemoveItemHandle(msg->easy_handle, msg->data.result);
        }

Can someone please enlighten me and explain what I'm doing wrong?

The problem is that when a request waits for response from the server,
curl_multi_perform does not seem to process other requests in its
internal queue.

I am using libcurl 7.14.0 under Linux and 7.15.1 on Win32.

--
_nimrod_a_abing_
Received on 2006-02-19