Movatterモバイル変換


[0]ホーム

URL:


everything curl

    Drive with multi_socket

    multi_socket is the extra spicy version of the regular multi interface and isdesigned for event-driven applications. Make sure you read theDrive with multi interface section first.

    multi_socket supports multiple parallel transfers—all done in the samesingle thread—and have been used to run several tens of thousands oftransfers in a single application. It is usually the API that makes the mostsense if you do a large number (>100 or so) of parallel transfers.

    Event-driven in this case means that your application uses a system levellibrary or setup that subscribes to a number of sockets and it lets yourapplication know when one of those sockets are readable or writable and ittells you exactly which one.

    This setup allows clients to scale up the number of simultaneous transfersmuch higher than with other systems, and still maintain good performance. Theregular APIs otherwise waste far too much time scanning through lists of allthe sockets.

    Pick one

    There are numerous event based systems to select from out there, and libcurlis completely agnostic to which one you use. libevent, libev and libuv arethree popular ones but you can also go directly to your operating system'snative solutions such as epoll, kqueue, /dev/poll, pollset or EventCompletion.

    Many easy handles

    Just like with the regular multi interface, you add easy handles to a multihandle withcurl_multi_add_handle(). One easy handle for each transfer youwant to perform.

    You can add them at any time while the transfers are running and you can alsosimilarly remove easy handles at any time using thecurl_multi_remove_handlecall. Typically though, you remove a handle only after its transfer iscompleted.

    multi_socket callbacks

    As explained above, this event-based mechanism relies on the application toknow which sockets that are used by libcurl and what activities libcurl waitsfor on those sockets: if it waits for the socket to become readable, writableor both.

    The application also needs to tell libcurl when the timeout time has expired,as it is control of driving everything libcurl cannot do it itself. libcurlinforms the application updated timeout values as soon as it needs to.

    socket_callback

    libcurl informs the application about socket activity to wait for with acallback calledCURLMOPT_SOCKETFUNCTION. Yourapplication needs to implement such a function:

    int socket_callback(CURL *easy,      /* easy handle */                    curl_socket_t s, /* socket */                    int what,        /* what to wait for */                    void *userp,     /* private callback pointer */                    void *socketp)   /* private socket pointer */{   /* told about the socket 's' */}/* set the callback in the multi handle */curl_multi_setopt(multi_handle, CURLMOPT_SOCKETFUNCTION, socket_callback);

    Using this, libcurl sets and removes sockets your application shouldmonitor. Your application tells the underlying event-based system to wait forthe sockets. This callback is called multiple times if there are multiplesockets to wait for, and it is called again when the status changes andperhaps you should switch from waiting for a writable socket to instead waitfor it to become readable.

    When one of the sockets that the application is monitoring on libcurl's behalfregisters that it becomes readable or writable, as requested, you tell libcurlabout it by callingcurl_multi_socket_action() and passing in the affectedsocket and an associated bitmask specifying which socket activity that wasregistered:

    int running_handles;ret = curl_multi_socket_action(multi_handle,                               sockfd, /* the socket with activity */                               ev_bitmask, /* the specific activity */                               &running_handles);

    timer_callback

    The application is in control and waits for socket activity. Even withoutsocket activity there are things libcurl needs to do. Timeout things, callingthe progress callback, starting over a retry or failing a transfer that takestoo long, etc. To make that work, the application must also make sure tohandle a single-shot timeout that libcurl sets.

    libcurl sets the timeout with the timer_callbackCURLMOPT_TIMERFUNCTION:

    int timer_callback(multi_handle,   /* multi handle */                   timeout_ms,     /* milliseconds to wait */                   userp)          /* private callback pointer */{  /* the new time-out value to wait for is in 'timeout_ms' */}/* set the callback in the multi handle */curl_multi_setopt(multi_handle, CURLMOPT_TIMERFUNCTION, timer_callback);

    There is only one timeout for the application to handle for the entire multihandle, no matter how many individual easy handles that have been added ortransfers that are in progress. The timer callback gets updated with thecurrent nearest-in-time period to wait. If libcurl gets called before thetimeout expiry time because of socket activity, it may update the timeoutvalue again before it expires.

    When the event system of your choice eventually tells you that the timer hasexpired, you need to tell libcurl about it:

    curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &running);

    …in many cases, this makes libcurl call the timer_callback again and set a newtimeout for the next expiry period.

    How to start everything

    When you have added one or more easy handles to the multi handle and set thesocket and timer callbacks in the multi handle, you are ready to start thetransfer.

    To kick it all off, you tell libcurl it timed out (because all easy handlesstart out with a short timeout) which make libcurl call the callbacks to setthings up and from then on you can just let your event system drive:

    /* all easy handles and callbacks are setup */curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &running);/* now the callbacks should have been called and we have sockets to wait   for and possibly a timeout, too. Make the event system do its magic */event_base_dispatch(event_base); /* libevent2 has this API *//* at this point we have exited the event loop */

    When is it done?

    The 'running_handles' counter returned bycurl_multi_socket_action holds thenumber of current transfers not completed. When that number reaches zero, weknow there are no transfers going on.

    Each time the 'running_handles' counter changes,curl_multi_info_read()returns info about the specific transfers that completed.


    [8]ページ先頭

    ©2009-2025 Movatter.jp