標籤:
Handle the Easy libcurl
To use the easy interface, you must first create yourself an easy handle. You need one handle for each easy session you want to perform. Basically, you should use one handle for every thread you plan to use for transferring. You must never share the same handle in multiple threads.
要使用easy介面,需要先建立easy handle.
一個handle用於一個easy session中,基本上就是說每個需要使用curl的線程,都要有自己的easy handle。
同一個Handle不可用於多個線程中。
Get an easy handle with
easyhandle = curl_easy_init();
這樣來擷取一個easy handle
easyhandle = curl_easy_init();
It returns an easy handle. Using that you proceed to the next step: setting up your preferred actions. A handle is just a logic entity for the upcoming transfer or series of transfers.
curl_easy_init()返回一個easy handle,獲得easy handle後再繼續進行下一步操作,一個handle是一個邏輯的實體,用於
即將執行的一個或多個資料轉送。
You set properties and options for this handle using curl_easy_setopt. They control how the subsequent transfer or transfers will be made. Options remain set in the handle until set again to something different. They are sticky. Multiple requests using the same handle will use the same options.
使用curl_easy_setopt設定Handle的屬性和選項。
這些設定在之後的資料轉送中生效,只要不修改這些屬性和選項,他們將一直生效。
If you at any point would like to blank all previously set options for a single easy handle, you can call curl_easy_reset and you can also make a clone of an easy handle (with all its set options) using curl_easy_duphandle.
如果想要清空easy handle中的屬性和選項,使用curl_easy_reset。
如果想要複製一個easy handle,使用curl_easy_duphandle。(複製會帶上原有的所有屬性和選項)
Many of the options you set in libcurl are "strings", pointers to data terminated with a zero byte. When you set strings with curl_easy_setopt, libcurl makes its own copy so that they don‘t need to be kept around in your application after being set[4].
libcurl中大多數選項都是string,以‘\0‘作為終止符。
使用curl_easy_setopt設定屬性後,你不需要儲存這個string,libcurl會複製string。
One of the most basic properties to set in the handle is the URL. You set your preferred URL to transfer with CURLOPT_URL in a manner similar to:
curl_easy_setopt(handle, CURLOPT_URL, "http://domain.com/");
handle最基礎的屬性設定就是設定URL,方法如下:
curl_easy_setopt(handle, CURLOPT_URL, "http://domain.com/");
Let‘s assume for a while that you want to receive data as the URL identifies a remote resource you want to get here. Since you write a sort of application that needs this transfer, I assume that you would like to get the data passed to you directly instead of simply getting it passed to stdout. So, you write your own function that matches this prototype:
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp);
我們假設你現在想要接收遠程URL的資料,
當你寫了一個簡短的程式, 我假設你想要直接接收資料而不是輸出到stdout。
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp);
You tell libcurl to pass all data to this function by issuing a function similar to this:
curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, write_data);
通過以下代碼發送資料:
curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, write_data);
You can control what data your callback function gets in the fourth argument by setting another property:
curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &internal_struct);
你可以使用回調參數控制資料,第四個參數是回調參數
curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &internal_struct);
Using that property, you can easily pass local data between your application and the function that gets invoked by libcurl. libcurl itself won‘t touch the data you pass with CURLOPT_WRITEDATA.
使用這個屬性,你可以輕鬆的傳輸本機資料,這個函數由libcurl喚醒。
libcurl本身不會修改CURLOPT_WRITEDATA屬性的資料
libcurl offers its own default internal callback that will take care of the data if you don‘t set the callback with CURLOPT_WRITEFUNCTION. It will then simply output the received data to stdout. You can have the default callback write the data to a different file handle by passing a ‘FILE *‘ to a file opened for writing with the CURLOPT_WRITEDATA option.
如果你沒有使用CURLOPT_WRITEFUNCTION設定回調,libcurl提供預設的內部回調,他會直接將收到的資料輸出到stdout。
你也可以使用CURLOPT_WRITEDATA,以及檔案指標‘FILE *‘,將資料寫入到檔案中。
Now, we need to take a step back and have a deep breath. Here‘s one of those rare platform-dependent nitpicks. Did you spot it? On some platforms[2], libcurl won‘t be able to operate on files opened by the program. Thus, if you use the default callback and pass in an open file with CURLOPT_WRITEDATA, it will crash. You should therefore avoid this to make your program run fine virtually everywhere.
在一些平台,libcurl不能操作通過程式開啟的檔案(在windows中,libcurl作為dll的情況下,不能這樣操作)。
因此,如果你使用預設的回調,並使用CURLOPT_WRITEDATA傳入一個已經開啟的檔案,會造成崩潰。
(CURLOPT_WRITEDATA was formerly known as CURLOPT_FILE. Both names still work and do the same thing).
CURLOPT_FILE是CURLOPT_WRITEDATA的前稱,現在仍然可用,含義不變。
If you‘re using libcurl as a win32 DLL, you MUST use the CURLOPT_WRITEFUNCTION if you set CURLOPT_WRITEDATA - or you will experience crashes.
如果libcurl在win32下作為dll使用,並且設定了CURLOPT_WRITEDATA,你必須使用CURLOPT_WRITEFUNCTION,否則崩潰。
There are of course many more options you can set, and we‘ll get back to a few of them later. Let‘s instead continue to the actual transfer:
success = curl_easy_perform(easyhandle);
設定了這麼多,我們先執行一下:
success = curl_easy_perform(easyhandle);
curl_easy_perform will connect to the remote site, do the necessary commands and receive the transfer. Whenever it receives data, it calls the callback function we previously set. The function may get one byte at a time, or it may get many kilobytes at once. libcurl delivers as much as possible as often as possible. Your callback function should return the number of bytes it "took care of". If that is not the exact same amount of bytes that was passed to it, libcurl will abort the operation and return with an error code.
curl_easy_perform會串連遠程伺服器,執行操作和接受資料。
當收到資料時,會調用之前設定的回呼函數。
函數可能一次接受1位元組,也能一次接受多個位元組,不一定,libcurl會盡量的投遞。
你的回呼函數應該返回接受到的位元組數。
如果傳輸的資料和預想中的不一致,libcurl會中斷,並返回錯誤碼。
When the transfer is complete, the function returns a return code that informs you if it succeeded in its mission or not. If a return code isn‘t enough for you, you can use the CURLOPT_ERRORBUFFER to point libcurl to a buffer of yours where it‘ll store a human readable error message as well.
當傳輸完成,函數會返回結果。
如果傳回值不夠用,可以使用CURLOPT_ERRORBUFFER擷取錯誤原因字串。
If you then want to transfer another file, the handle is ready to be used again. Mind you, it is even preferred that you re-use an existing handle if you intend to make another transfer. libcurl will then attempt to re-use the previous connection.
如果你想要傳輸其他檔案,handle已經可以再次使用了,libcurl會重用handle
For some protocols, downloading a file can involve a complicated process of logging in, setting the transfer mode, changing the current directory and finally transferring the file data. libcurl takes care of all that complication for you. Given simply the URL to a file, libcurl will take care of all the details needed to get the file moved from one machine to another.
某些協議下載檔案的過程可能比較複雜,例如登陸、設定傳輸模式、目錄切換,最後才是傳輸資料。
libcurl會幫你處理這些複雜的流程。
Multi-threading Issues
多線程問題
The first basic rule is that you must never simultaneously share a libcurl handle (be it easy or multi or whatever) between multiple threads. Only use one handle in one thread at any time. You can pass the handles around among threads, but you must never use a single handle from more than one thread at any given time.
基本原則是不能在多線程中共用libcurl handle(easy 、multi什麼的都不可以)。
一個handle同時只能在一個線程中使用。
你可以線上程間傳遞handle,但是不能同時使用。
libcurl is completely thread safe, except for two issues: signals and SSL/TLS handlers. Signals are used for timing out name resolves (during DNS lookup) - when built without using either the c-ares or threaded resolver backends.
libcurl是安全執行緒的,除了2個問題:
signals 和 SSL/TLS handle。
訊號用於DNS lookup中。
If you are accessing HTTPS or FTPS URLs in a multi-threaded manner, you are then of course using the underlying SSL library multi-threaded and those libs might have their own requirements on this issue. Basically, you need to provide one or two functions to allow it to function properly. For all details, see this:
如果在多線程中訪問HTTPS和FTPS的URL,肯定會用到SSL庫
OpenSSL
http://www.openssl.org/docs/crypto/threads.html#DESCRIPTION
GnuTLS
http://gnutls.org/manual/html_node/Thread-safety.html
NSS
is claimed to be thread-safe already without anything required.
PolarSSL
Required actions unknown.
yassl
Required actions unknown.
axTLS
Required actions unknown.
Secure Transport
The engine is fully thread-safe, and no additional steps are required.
When using multiple threads you should set the CURLOPT_NOSIGNAL option to 1 for all handles. Everything will or might work fine except that timeouts are not honored during the DNS lookup - which you can work around by building libcurl with c-ares support. c-ares is a library that provides asynchronous name resolves. On some platforms, libcurl simply will not function properly multi-threaded unless this option is set.
Also, note that CURLOPT_DNS_USE_GLOBAL_CACHE is not thread-safe.
[譯]libcurl_tutorial