`
dxx16dxx
  • 浏览: 13586 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

使用 cURL 和 libcurl 通过 Internet 进行对话

 
阅读更多

使用 cURL 和 libcurl 通过 Internet 进行对话
2010年09月10日
  Tim M. Jones, 顾问工程师, 
  2009 年 10 月 29 日 cURL 是一个命令行工具,可以对文件传输使用许多协议,包括 HTTP、FTP、Secure Copy (SCP)、Telnet 等等。但是,除了可以用命令行通过 Internet 与端点对话外,还可以使用 libcurl 编写简单或复杂的程序,以自动化执行应用层的协议任务。本文将介绍 cURL 命令行工具,然后向您展示如何使用 libcurl 以及 C 和 Python 构建一个 HTTP 客户端。
  开发 HTTP 和 FTP 之类依赖于应用层协议的应用程序并不复杂,但也不简单。进一步讲,这不是应用程序的重点,因为大部分情况下,协议之上的内容才是真正重要的内容。因此,libcurl 引起了许多人的兴趣,因为它的重点是应用程序而不是开发的各个方面。注意,很少有应用程序开发自己的 TCP/IP 堆栈,所以老话重提:尽可能重用以最小化开发安排并提高应用程序的可靠性。
  本文首先简单介绍应用层协议,然后介绍 cURL、libcurl 并解释它们的用法。
  Web 协议
  如今构建应用程序已与过去大不相同。现在的应用程序需要能够通过网络或 Internet 进行通讯(提供人类可用的网络 API 或接口),还要能支持用户脚本化以提高灵活性。现代应用程序通常使用 HTTP 公开 Web 接口,并通过 Simple Mail Transport Protocol (SMTP) 提供警告通知。这些协议允许您将 Web 浏览器指向设备以获得配置或状态信息,并从设备或常用的电子邮件客户端接收标准电子邮件(分别通过 HTTP 和 SMTP)。
  这些 Web 服务通常构建在网络堆栈的套接字层上(见图 1)。套接字层实现一个最先出现在 Berkeley Software Distribution (BSD) 操作系统上的 API,并提取底层传输和网络层协议的详细信息。 
  
  Web 服务发生在客户端和服务器之间的协议对话中。在 HTTP 上下文中,服务器是终端设备,客户端是位于端点上的浏览器。对于 SMTP,服务器是邮件网关或端点用户,客户端是终端设备。在某些情况下,协议对话发生在两个步骤(请求和响应)中,但另一些情况下,需要协商和通讯的通信量更多。这种协商可能增加了大量复杂性,这可以通过 API 进行抽象,比如 libcurl。 cURL 简介 cURL 的起源与发展
  cURL 是 Daniel Stenberg 发明的,但是 600 多名开发人员也做出了巨大的贡献。它无疑是许多应用程序都使用的有用技术之一。 
  cURL 最初的设计初衷是使用不同的协议(比如 FTP、HTTP、SCP 等)在端点之间移动文件。它最初是一个命令行实用工具,但现在也是一个绑定了 30 多种语言的库。因此,现在不仅可以通过 shell 使用 cURL,您还可以构建合并了这个重要功能的应用程序。libcurl 库也是可以移植的,支持 Linux??、IBM??AIX??操作系统、BSD、Solaris 以及许多其他 UNIX??变体。 获取和安装 cURL/libcurl 获取和安装 libcurl 非常简单,取决于您所运行的 Linux 发行版。如果运行的是 Ubuntu,您可以使用 apt-get轻松安装这些包。以下行演示了如何为 libcurl 安装 libcurl 和 Python 绑定: apt-get实用工具确保该过程满足所有的依赖关系。 在命令行中使用 cURL
  cURL 最开始是一个命令行工具,可以使用 Uniform Resource Locator (URL) 语法执行数据传输。考虑到它在命令行上的流行度,后来创建了一个可以在应用程序中生成这些行为的库。如今,命令行 cURL 是 cURL 库的包装器。本文首先研究 cURL 作为命令行的功能,然后深入探讨如何将它作为库使用。
  cURL 的两种常见用法是使用 HTTP 和 FTP 协议进行文件传输。cURL 为这些协议提供一个简单的接口。要使用 HTTP 从网站获取文件,只需告诉 cURL 您要将网页写入到其中的本地文件的文件名、网站的 URL 以及要获取的文件。让我们看一下清单 1 中的简单命令行示例。 注意,由于我指定了域而不是文件,我将获得根文件(index.html)。要使用 cURL 将该文件移动到 FTP 站点,可以使用 -T选项指定要上传的文件,然后提供 FTP 站点的 URL 以及文件的路径。 是不是很简单?学习了一些模式之后您会发现,cURL 使用起来非常简单。但是您可以使用的选项非常多 -在 cURL 命令行中请求帮助(使用 --help)可以得到 129 行选项。如果您觉得这还不算太多,那么还有一大批其他控制选项(从详细度到安全性),以及特定于协议的配置项。 从开发人员的角度看,这还不算是 cURL 最令人兴奋的地方。让我们深入了解 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 的 HTTP 客户端
  C API 在 libcurl 功能上提供了两个 API。easy 接口是一个简单的同步 API(意味着当您使用请求调用 libcurl 时,将能够满足您的请求,直到完成或发生错误)。多接口可以进一步控制 libcurl,您的应用程序可以执行多个同步传输,并控制 libcurl 何时何地移动数据。
  该示例使用 easy 接口。该 API 还能控制数据移动过程(使用回调),但正如其名称所示,使用起来非常简单。清单 3 提供了 HTTP 的 C 语言示例。  #include  #include  #include  #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 数据被提取,它也可以丢弃该数据。这就是从网站将文件读取到内存的相对简单的方法。 基于 Python 的 HTTP 客户端
  本节提供的示例类似于基于 C 的 HTTP 客户端,不过它使用的是 Python。Python 是一种非常有用的面向对象的脚本语言,在原型化和构建生产软件方面非常突出。示例假设您较熟悉 Python,但使用不多,因此不要期望过高。 这个简单的 Python HTTP 客户端使用 pycurl,如清单 4 所示。 使用 Python 进行原型化
  原型化是 Python 的优势之一。它只需很少的代码就可以实现大量功能。使用 C 也许能获得更好的性能,但是如果您的目的是快速编码以证明某个概念,那么高级脚本语言是无可替代的,比如 Python。 这比 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。它一定能大大减少您的开发时间,并找回编码的乐趣。 参考资料 cURL是一个命令行工具和库,实现了各种客户端协议。它支持 12 种以上的协议,包括 FTP、HTTP、Telnet 以及其他安全变体。许多平台上都能找到 cURL,包括 Linux、AIX、BSD 和 Solaris,它支持 30 多种语言。
  PycURL是 libcurl API 之上的一个薄层,PycURL 速度非常快。使用 PycURL,您可以使用 libcurl 库开发 Python 应用程序。
  说到应用程序灵活性,您可以在 "用 Guile 编写脚本" 中了解更多有关将脚本功能集成到应用程序的内容。
  要收听有关软件开发人员的有趣采访和讨论,请查看 developerWorks 网络广播。
  了解最新的 developerWorks 技术活动 和 网络广播。
  在 Twitter 上跟随 developerWorks。
  查阅最近将在全球举办的面向 IBM 开放源码开发人员的研讨会、交易展览、网络广播和其他 活动。
  访问 developerWorks 开源专区获得丰富的 how-to 信息、工具和项目更新,帮助您用开放源码技术进行开发,并与 IBM 产品结合使用。
  查看免费的 developerWorks On demand 演示,观看并了解 IBM 及开源技术和产品功能。
  使用 IBM 试用软件改进您的下一个开发项目,这些软件可以通过下载中心获得。
  下载 IBM 产品评估版 或 在 IBM SOA Sandbox 中研究在线试用版,开始使用来自 DB2??、Lotus??、Rational??、Tivoli??和 WebSphere??的应用程序开发工具和中间件产品。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics