標籤:curl c libcurl 文檔 linux
0. 為使用的curl url 添加確定的協議頭
原文:
If you specify URL without protocol:// prefix, curl will attempt to guess what protocol you might want. It will then default to HTTP but try other protocols based on often-used host name prefixes. For example, for host names starting with "ftp." curl will assume you want to speak FTP.
1. 把 curl_easy_perform() 回調資料直接寫到檔案中(FILE *)
原文:
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.
源碼中的實現:
這樣,就可以少寫一個回呼函數了(喂,你是有多懶啊),樣本如下
FILE *fp;fp = fopen("/root/test.bmp", "wb");...curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);...fclose(fp);
2. curl_easy_perform 返回值處理
使用 CURLOPT_ERRORBUFFER 儲存錯誤, buf_size=CURL_ERROR_SIZE
或使用 curl_easy_strerror(res) (感覺這個簡便)
樣本:
/* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if(res != CURLE_OK) { printf("%s curl_easy_perform() error! \n", __FUNCTION__); printf("error msg = %s\n", curl_easy_strerror(res)); return -1; }
3. 多線程環境配置 CURLOPT_NOSIGNAL
原文:
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.
對於 CURLOPT_TIMEOUT(預設0), CURLOPT_CONNECTTIMEOUT(預設300)選項:
In unix-like systems, this might cause signals to be used unless CURLOPT_NOSIGNAL is set.
4. 設定 CURLOPT_VERBOSE、CURLOPT_HEADER 的必要性
原文:
There‘s one golden rule when these things occur: set the CURLOPT_VERBOSE option to 1. It‘ll cause the library to spew out the entire protocol details it sends, some internal info and some received protocol data as well (especially when using FTP). If you‘re using HTTP, adding the headers in the received output to study is also a clever way to get a better understanding why the server behaves the way it does. Include headers in the normal body output with CURLOPT_HEADER set 1.
經實驗:
設定 curl_easy_setopt(curl, CURLOPT_HEADER, 1L) 後,回呼函數會返回 http頭相關資訊(原本是直接輸出到stdout的),考慮到還要過濾這些資訊,所以還是不要設定這個了
5. curl post 注意事項
原文:
Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header. You can disable this header with CURLOPT_HTTPHEADER as usual.
解釋:
當使用libcurl的POST方式時,如果POST資料的大小大於1024個位元組,libcurl不會直接發送POST請求,而是會分為兩步執行請求:
<1> 發送一個請求,該要求標頭部包含一個Expect: 100-continue的欄位,用來詢問server是否願意接受資料
<2> 當接收到從server返回的100-continue的應答後,它才會真正的發起POST請求,將資料發送給server。
對於“100-continue"這個欄位,RFC文檔(http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3)是這麼解釋的:
它可以讓用戶端在發送請求資料之前去判斷伺服器是否願意接收該資料,如果伺服器願意接收,用戶端才會真正發送資料,
這麼做的原因是如果用戶端直接發送請求資料,但是伺服器又將該請求拒絕的話,這種行為將帶來很大的資源開銷。
所以為了避免這種情況,libcurl在發送大於1024位元組的POST請求時採用了這種方法,但是相對的,它會引起請求延遲的加大,
另外並不是所有的server都會正確處理並且應答”100-continue“,比如lighttpd,就會返回417”Expectation Failed“,造成請求邏輯出錯。
解決辦法:
// POST資料的大於1024個位元組struct curl_slist *headerlist = NULL;static const char buf[] = "Expect:";headerlist = curl_slist_append(headerlist, buf); /* initalize custom header list */curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); /* set header*/curl_slist_free_all(headerlist); /* free slist */
6. 回呼函數的正確返回
return (size * nmemb);
原因:
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.
如果回呼函數中接收的資料有誤,個人感覺可以返回0或者返回你已經處理的資料數,
因為源碼的處理如下:
/* If the previous block of data ended with CR and this block of data is just a NL, then the length might be zero */ // len 為要發送給回呼函數的資料長度 if(len) { wrote = data->set.fwrite_func(ptr, 1, len, data->set.out); } else { wrote = len; }if(wrote != len) { failf(data, "Failed writing body (%zu != %zu)", wrote, len); return CURLE_WRITE_ERROR;}
libcurl 使用的幾個注意事項