cURL 是一個命令行工具,可以對文件傳輸使用許多協議,包括 HTTP、FTP、Secure Copy (SCP)、Telnet 等等。但是,除了可以用命令行通過 Internet 與端點對話外,還可以使用 libcurl 編寫簡單或復雜的程序,以自動化執行應用層的協議任務。本文將介紹 cURL 命令行工具,然后向您展示如何使用 libcurl 以及 C 和 Python 構建一個 HTTP 客戶端。
開發 HTTP 和 FTP 之類依賴于應用層協議的應用程序并不復雜,但也不簡單。進一步講,這不是應用程序的重點,因為大部分情況下,協議之上的內容才是真正重要的內容。因 此,libcurl 引起了許多人的興趣,因為它的重點是應用程序而不是開發的各個方面。注意,很少有應用程序開發自己的 TCP/IP 堆棧,所以老話重提:盡可能重用以最小化開發安排并提高應用程序的可靠性。
本文首先簡單介紹應用層協議,然后介紹 cURL、libcurl 并解釋它們的用法。
如 今構建應用程序已與過去大不相同。現在的應用程序需要能夠通過網絡或 Internet 進行通訊(提供人類可用的網絡 API 或接口),還要能支持用戶腳本化以提高靈活性?,F代應用程序通常使用 HTTP 公開 Web 接口,并通過 Simple Mail Transport Protocol (SMTP) 提供警告通知。這些協議允許您將 Web 瀏覽器指向設備以獲得配置或狀態信息,并從設備或常用的電子郵件客戶端接收標準電子郵件(分別通過 HTTP 和 SMTP)。
這些 Web 服務通常構建在網絡堆棧的套接字層上(見圖 1)。套接字層實現一個最先出現在 Berkeley Software Distribution (BSD) 操作系統上的 API,并提取底層傳輸和網絡層協議的詳細信息。
Web 服務發生在客戶端和服務器之間的協議對話中。在 HTTP 上下文中,服務器是終端設備,客戶端是位于端點上的瀏覽器。對于 SMTP,服務器是郵件網關或端點用戶,客戶端是終端設備。在某些情況下,協議對話發生在兩個步驟(請求和響應)中,但另一些情況下,需要協商和通訊的通 信量更多。這種協商可能增加了大量復雜性,這可以通過 API 進行抽象,比如 libcurl。
cURL 最初的設計初衷是使用不同的協議(比如 FTP、HTTP、SCP 等)在端點之間移動文件。它最初是一個命令行實用工具,但現在也是一個綁定了 30 多種語言的庫。因此,現在不僅可以通過 shell 使用 cURL,您還可以構建合并了這個重要功能的應用程序。libcurl 庫也是可以移植的,支持 Linux?、IBM?AIX?操作系統、BSD、Solaris 以及許多其他 UNIX?變體。
獲取和安裝 libcurl 非常簡單,取決于您所運行的 Linux 發行版。如果運行的是 Ubuntu,您可以使用
apt-get
輕松安裝這些包。以下行演示了如何為 libcurl 安裝 libcurl 和 Python 綁定:
$ sudo apt-get install libcurl3 $ sudo apt-get install python-pycurl |
?
apt-get
實用工具確保該過程滿足所有的依賴關系。
cURL 最開始是一個命令行工具,可以使用 Uniform Resource Locator (URL) 語法執行數據傳輸。考慮到它在命令行上的流行度,后來創建了一個可以在應用程序中生成這些行為的庫。如今,命令行 cURL 是 cURL 庫的包裝器。本文首先研究 cURL 作為命令行的功能,然后深入探討如何將它作為庫使用。
cURL 的兩種常見用法是使用 HTTP 和 FTP 協議進行文件傳輸。cURL 為這些協議提供一個簡單的接口。要使用 HTTP 從網站獲取文件,只需告訴 cURL 您要將網頁寫入到其中的本地文件的文件名、網站的 URL 以及要獲取的文件。讓我們看一下清單 1 中的簡單命令行示例。
$
curl -o test html www.exampledomain.com
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 43320 100 43320 0 0 55831 0 --:--:-- --:--:-- --:--:-- 89299
$
|
?
注意,由于我指定了域而不是文件,我將獲得根文件(index.html)。要使用 cURL 將該文件移動到 FTP 站點,可以使用
-T
選項指定要上傳的文件,然后提供 FTP 站點的 URL 以及文件的路徑。
清單 2. 使用 cURL 將
文件上傳
到 FTP 站點的示例
$
curl -T test.html ftp://user:password@ftp.exampledomain.com/ftpdir/
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 43320 0 0 100 43320 0 38946 0:00:01 0:00:01 --:--:-- 124k
$
|
?
是不是很簡單?學習了一些模式之后您會發現,cURL 使用起來非常簡單。但是您可以使用的選項非常多 —在 cURL 命令行中請求幫助(使用
--help
)可以得到 129 行選項。如果您覺得這還不算太多,那么還有一大批其他控制選項(從詳細度到安全性),以及特定于協議的配置項。
從開發人員的角度看,這還不算是 cURL 最令人興奮的地方。讓我們深入了解 cURL 庫,學習如何向應用程序添加文件傳輸協議。
如 果您有 10 年以上的腳本語言經驗,您就會注意到它們的標記有很大的變化。Python、Ruby、Perl 等這些腳本語言不僅包含套接字層(C 或 C++ 中也有),還包含了應用層協議 API。這些腳本語言合并了高級功能,可以創建 HTTP 服務器或客戶端。libcurl 庫為 C 和 C++ 之類的語言添加了類似的功能,但是它可以在不同的語言之間移植。在所有它支持的語言中都能找到與 libcurl 相當的行為,但是由于這些語言的差異很大(設想一下 C 和 Scheme),提供這些行為的方式也很不相同。
libcurl 庫以 API 的形式封裝清單 1 和清單 2 中描述的行為,因此它可以被高級語言使用(如今已超過 30 種)。本文提供了 libcurl 的兩個示例。第一個示例研究使用 c 構建的簡單 HTTP 客戶端(適合構建 Web 爬行器),第二個示例是一個使用 Python 創建的簡單 HTTP 客戶端。
C API 在 libcurl 功能上提供了兩個 API。easy 接口是一個簡單的同步 API(意味著當您使用請求調用 libcurl 時,將能夠滿足您的請求,直到完成或發生錯誤)。多接口可以進一步控制 libcurl,您的應用程序可以執行多個同步傳輸,并控制 libcurl 何時何地移動數據。
該示例使用 easy 接口。該 API 還能控制數據移動過程(使用回調),但正如其名稱所示,使用起來非常簡單。清單 3 提供了 HTTP 的 C 語言示例。
清單 3. 使用 libcurl easy 接口的 C HTTP 客戶端
#include <stdio.h> #include <string.h> #include <curl/curl.h> #define MAX_BUF 65536 char wr_buf[MAX_BUF+1]; int wr_index; /* * Write data callback function (called within the context of * curl_easy_perform. */ size_t write_data( void *buffer, size_t size, size_t nmemb, void *userp ) { int segsize = size * nmemb; /* Check to see if this data exceeds the size of our buffer. If so, * set the user-defined context value and return 0 to indicate a * problem to curl. */ if ( wr_index + segsize > MAX_BUF ) { *(int *)userp = 1; return 0; } /* Copy the data from the curl buffer into our buffer */ memcpy( (void *)&wr_buf[wr_index], buffer, (size_t)segsize ); /* Update the write index */ wr_index += segsize; /* Null terminate the buffer */ wr_buf[wr_index] = 0; /* Return the number of bytes received, indicating to curl that all is okay */ return segsize; } /* * Simple curl application to read the index.html file from a Web site. */ int main( void ) { CURL *curl; CURLcode ret; int wr_error; wr_error = 0; wr_index = 0; /* First step, init curl */ curl = curl_easy_init ; if (!curl) { printf("couldn't init curl\n"); return 0; } /* Tell curl the URL of the file we're going to retrieve */ curl_easy_setopt ( curl, CURLOPT_URL, "www.exampledomain.com" ); /* Tell curl that we'll receive data to the function write_data, and * also provide it with a context pointer for our error return. */ curl_easy_setopt ( curl, CURLOPT_WRITEDATA, (void *)&wr_error ); curl_easy_setopt ( curl, CURLOPT_WRITEFUNCTION, write_data ); /* Allow curl to perform the action */ ret = curl_easy_perform ( curl ); printf( "ret = %d (write_error = %d)\n", ret, wr_error ); /* Emit the page if curl indicates that no errors occurred */ if ( ret == 0 ) printf( "%s\n", wr_buf ); curl_easy_cleanup ( curl ); return 0; } |
?
最上方是必需的
include
文件,包括 cURL 根文件。接下來,我定義了兩個用于傳輸的變量。第一個變量是
wr_buf
,表示將在其中寫入傳入數據的緩沖區。
wr_index
表示緩沖區的當前寫入索引。
轉到
main
函數,該函數使用 easy API 進行設置。所有 cURL 調用都通過維護特定請求狀態的句柄進行操作。這稱為
CURL
指針引用。本例還創建一個特殊的返回碼,稱為
CURLcode
。在使用任何 libcurl 函數之前,您需要調用
curl_easy_init
獲取
CURL
句柄。接下來,注意
curl_easy_setopt
調用的數量。它們為特定的操作配置句柄。對于這些調用,您提供句柄、命令和選項。首先,本例使用
CURLOPT_URL
指定要獲取的 URL。然后,它使用
CURL_WRITEDATA
提供一個上下文變量(在本例中,它是內部的 write 錯誤變量)。最后,它使用
CURLOPT_WRITEFUNCTION
指定數據可用時應該調用的函數。在啟動 API 之后,API 將使用它讀取的數據多次調用該函數。
要開始傳輸,調用
curl_easy_perform
。它的工作是根據之前的配置執行傳輸。調用該函數時,在完成傳輸或發生錯誤之前該函數不會返回。
main
的最后一步是提交返回狀態,提交頁面讀取,最后使用
curl_easy_cleanup
清除(當使用句柄執行完操作后)。
現在看看
write_data
函數。該函數是針對特定操作收到數據時調用的回調。注意,當您從網站讀取數據時,將寫入該數據(
write_data
)。將向回調提供一個緩沖區(包含可用數據)、成員數量和大?。ň彌_中可用數據總量)、上下文指針。第一個任務是確保緩沖區(
wr_buf
)的空間足以寫入數據。如果不夠,它將設置上下文指針并返回 0,表示出現問題。否則,它將 cURL 緩沖區的數據復制到您的緩沖區,并增加索引,指向要寫入的下一個位置。本例還終止字符串,稍后可以對其使用
printf
。最后,它返回 libcurl 操作的字節數量。這將告訴 libcurl 數據被提取,它也可以丟棄該數據。這就是從網站將文件讀取到內存的相對簡單的方法。
本節提供的示例類似于基于 C 的 HTTP 客戶端,不過它使用的是 Python。Python 是一種非常有用的面向對象的腳本語言,在原型化和構建生產軟件方面非常突出。示例假設您較熟悉 Python,但使用不多,因此不要期望過高。
這個簡單的 Python HTTP 客戶端使用
pycurl
,如清單 4 所示。
清單 4. 使用 libcurl 的
pycurl
接口的 Python HTTP 客戶端
import sys import pycurl wr_buf = '' def write_data( buf ): global wr_buf wr_buf += buf def main: c = pycurl.Curl c. setopt ( pycurl.URL, 'http://www.exampledomain.com' ) c. setopt ( pycurl.WRITEFUNCTION, write_data ) c. perform c. close main sys.stdout.write(wr_buf)
這比 C 語言版本簡單的多。它首先導入必需的模塊(用于標準系統的
sys
和
pycurl
模塊)。接下來,它定義 write 緩沖區(
wr_buf
)。像 C 程序中一樣,我聲明一個
write_data
函數。注意,該函數只有一個參數:從 HTTP 服務器中讀取的數據緩沖區。我將該緩沖區連接到全局 write 緩沖區。
main
函數首先創建一個
Curl
句柄,然后使用
setopt
方法為傳輸定義
URL
和
WRITEFUNCTION
。它調用
perform
方法啟動傳輸并關閉句柄。最后,它調用
main
函數,并將 write 緩沖區提交到
stdout
。注意,在這種情況下,您不需要錯誤上下文指針,因為您使用了 Python 字符串連接,這就是說您不會使用大小固定的字符串。
本文僅僅簡單介紹了 libcurl,介紹了它支持的多種協議和語言。希望這能夠展示它如何輕松構建使用應用層協議(如 HTTP)的應用程序。libcurl 網站提供了很多示例和有用的文檔。下一次開發 Web 瀏覽器、爬行器或其他有應用層協議要求的應用程序時,試試 libcurl。它一定能大大減少您的開發時間,并找回編碼的樂趣。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
