使用 cURL 和 libcurl 通过 Internet 进行对话
来源:互联网 发布:淘宝交易指数在哪里看 编辑:程序博客网 时间:2024/05/18 19:45
使用 cURL 和 libcurl 通过 Internet 进行对话
将 libcurl 与 C 以及 Python 结合使用
简介: cURL 是一个命令行工具,可以对文件传输使用许多协议,包括 HTTP、FTP、Secure Copy (SCP)、Telnet 等等。但是,除了可以用命令行通过 Internet 与端点对话外,还可以使用 libcurl 编写简单或复杂的程序,以自动化执行应用层的协议任务。本文将介绍 cURL 命令行工具,然后向您展示如何使用 libcurl 以及 C 和 Python 构建一个 HTTP 客户端。
发布日期: 2009 年 10 月 29 日
级别: 初级
其他语言版本: 英文
访问情况 : 9729 次浏览
评论: 0 (查看 | 添加评论 - 登录)
为本文评分
开发 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,并提取底层传输和网络层协议的详细信息。
图 1. 网络堆栈和 libcurl
Web 服务发生在客户端和服务器之间的协议对话中。在 HTTP 上下文中,服务器是终端设备,客户端是位于端点上的浏览器。对于 SMTP,服务器是邮件网关或端点用户,客户端是终端设备。在某些情况下,协议对话发生在两个步骤(请求和响应)中,但另一些情况下,需要协商和通讯的通信量更多。这种协商可能增加了大量复杂性,这可以通过 API 进行抽象,比如 libcurl。
回页首
cURL 简介
cURL 最初的设计初衷是使用不同的协议(比如 FTP、HTTP、SCP 等)在端点之间移动文件。它最初是一个命令行实用工具,但现在也是一个绑定了 30 多种语言的库。因此,现在不仅可以通过 shell 使用 cURL,您还可以构建合并了这个重要功能的应用程序。libcurl 库也是可以移植的,支持 Linux®、IBM®AIX®操作系统、BSD、Solaris 以及许多其他 UNIX®变体。
回页首
获取和安装 cURL/libcurl
获取和安装 libcurl 非常简单,取决于您所运行的 Linux 发行版。如果运行的是 Ubuntu,您可以使用 apt-get
轻松安装这些包。以下行演示了如何为 libcurl 安装 libcurl 和 Python 绑定:
$ sudo apt-get install libcurl3 $ sudo apt-get install python-pycurl
apt-get
实用工具确保该过程满足所有的依赖关系。
回页首
在命令行中使用 cURL
cURL 最开始是一个命令行工具,可以使用 Uniform Resource Locator (URL) 语法执行数据传输。考虑到它在命令行上的流行度,后来创建了一个可以在应用程序中生成这些行为的库。如今,命令行 cURL 是 cURL 库的包装器。本文首先研究 cURL 作为命令行的功能,然后深入探讨如何将它作为库使用。
cURL 的两种常见用法是使用 HTTP 和 FTP 协议进行文件传输。cURL 为这些协议提供一个简单的接口。要使用 HTTP 从网站获取文件,只需告诉 cURL 您要将网页写入到其中的本地文件的文件名、网站的 URL 以及要获取的文件。让我们看一下清单 1 中的简单命令行示例。
清单 1. 使用 cURL 从网站获取文件的示例
$ 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 库,学习如何向应用程序添加文件传输协议。
回页首
作为库的 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 语言示例。
清单 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 数据被提取,它也可以丢弃该数据。这就是从网站将文件读取到内存的相对简单的方法。
回页首
基于 Python 的 HTTP 客户端
本节提供的示例类似于基于 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。它一定能大大减少您的开发时间,并找回编码的乐趣。
- 使用 cURL 和 libcurl 通过 Internet 进行对话
- 使用 cURL 和 libcurl 通过 Internet 进行对话
- Curl和libcurl使用
- libcurl和curl简介
- cURL简单使用、libcurl编程
- cURL简单使用、libcurl编程
- curl 和 libcurl 小技巧
- curl libcurl
- curl的基本使用及libcurl
- cURL简单使用、libcurl编程, curl_easy_setopt
- 网络传输工具cURL和libcurl
- 通过使用libcurl POST数据和上传与下载文件
- cocos2dx 使用libcurl进行文件传输
- 使用libcurl进行文件上传
- 使用libcurl进行文件上传
- libcurl库的使用(通过libcurl库下载url图像)
- 微信服务器和第三方服务器之间究竟是通过什么方式进行对话的?
- 如何使用curl进行验证码生成和验证
- 致我们终将逝去的青春 盘点中国最美十大校园
- windows 如何查看端口占用情况
- Ubuntu设置ip地址
- 2012年5月9日 声音
- linux ipc—管道
- 使用 cURL 和 libcurl 通过 Internet 进行对话
- Centos 搭建ftp服务器
- 自定义标签开发入门
- shell 判断文件、目录是否存在
- Hibernate中Session接口的用法
- u-boot 使用 jffs2 文件系统加载内核 备忘
- 如何在android中调用数据库资源
- 设计一个移动应用的本地缓存机制
- 剑指offer第6题 二叉树重建 九度OJ1385