TimothyQiu's Blog

Happy coding

一道笔试题

libcurl

timothyqiu posted @ 2010年2月24日 05:10 in 学习笔记 with tags c/c++ libcurl , 4426 阅读

话说本来想做个校内桌面客户端用来方便我接受和发送状态的(不喜欢人人桌面),结果把基础的东西弄好后发现虽然人人开放平台的开发类型里有桌面应用的选项,但桌面 API 没有开放 = = 真是怨念啊……不过 libcurl 依旧强大,很好玩~所以写一下。

libcurl 是鼎鼎大名的开源客户端 URL 传输库,支持 FTP、HTTP 以及其它很多乱七八糟的协议。在各种语言上的实现也很多:C、C++、Lua、Java、Pascal、Perl、PHP、Python、Ruby、Visual Basic……。这里说最常用的 C 语言实现。我的环境是 Windows XP + MinGW32。


1. 下载 libcurl 库

libcurl 可以在其官网获得。Download 页有源代码和为各平台预编译的二进制文件(curl 程序)和开发包(include + lib + doc)下载。不过我想要的 MinGW32 开发包的链接失效了 = = 就下载个源代码包自己编译吧。

在 Download 页的 Source Archives 栏里有目前最新的 curl 7.20.0 版本源代码压缩包,下载 curl-7.20.0.zip 文件。

2. 编译 libcurl 库

  1. 解压 curl-7.20.0.zip 文件。
  2. 通过命令提示符进入 curl-7.20.0 文件夹。
  3. 输入 mingw32-make mingw32 进行编译。(这里我只需要普通的功能,于是没有加一些附加的选项)

编译完成后,在 lib 文件夹中会有我们需要的三个文件。

  • libcurl.a 静态链接库
  • libcurldll.a 动态链接库的导入库
  • libcurl.dll 动态链接库

接下来,可以进入 doc/examples 文件夹,测试编译一些示例程序。可以直接 make 现成的 Makefile.m32 文件,也可以手动一个个用 gcc 编译。

动态链接:

gcc -I../../include -L../../lib simple.c -lcurldll

静态链接:

gcc -I../../include -L../../lib simple.c -DCURL_STATICLIB -lcurl -lws2_32 -lwldap32

动态链接编译出的程序运行时依赖 libcurl.dll。静态链接参数中的 ws2_32 是 Windows Socket 2 库,wldap32 是微软的 Lightweight Directory Access Protocol API 库。

3. GET 到内存中

最简单的示例可以看 doc/examples 下的 simple.c 文件,演示如何将 curl 主页内容输出到 stdout。可以看到,基本的 curl 程序主要分四步:

  1. curl_easy_init 创建 CURL 对象
  2. curl_easy_setopt 设置操作选项
  3. curl_easy_perform 进行操作
  4. curl_easy_cleanup 销毁 CURL 对象

simple.c 演示的是将取到的网页内容输出到 stdout,如果是输出到文件,只要给 WRITEDATA 选项一个有效的 FILE 指针即可。那么,要直接读入内存该怎么设置呢?(可以参考 doc/examples/getinmemory.c,不过指针看着头大,所以下面进行一些修改,用 C++ 的 std::string 来简化缓冲区内存分配操作,相对比较简单易懂)

选项 WRITEDATA 的作用是指定传给回调函数的最后一个参数,作为缓冲区使用。这里设置一个指向 std::string 类型的变量 g_buffer 的指针。

选项 WRITEFUNCTION 的作用是指定处理接收数据的回调函数。这里设置为下面这个函数:

/**
 * 处理接收数据的回调函数
 * @param data 指传入本次传输所收到的数据片
 * @param size 参数 data 所指向数据的大小即为 size * nmemb
 * @param nmemb
 * @param buffer 传入指向 g_buffer 的指针
 * @return 本次传输已处理的数据大小
 */
size_t writefunc(char *data, size_t size, size_t nmemb, std::string *buffer)
{
    if (!data) return 0; // 有可能传输空数据
   
    buffer->append(data, size * nmemb); // 将得到的部分数据附加到缓冲区结尾
    return size * nmemb; 
}

于是 curl_easy_perform 返回后,g_buffer 中即为取得的网页内容。

ps. 显而易见,如果要连续进行两次 perform 的话,后一次执行之前先要调用 g_buffer.clear() 方法。注意不要用 g_buffer = "",否则 g_buffer 的地址就改变了(如果你不想再 setopt 一次的话)。

4. HTTP POST

libcurl 实现 POST 操作可以参照 doc/examples/http-post.c 文件。即设置 POSTFIELDS 选项为要 POST 的数据即可。

人人开放平台的 REST API 是通过 HTTP 向 http://api.renren.com/restserver.do 服务器 POST 各种参数,服务器返回一个 XML 文件(或者 JSON)实现交互的。

POST 的数据格式类似 key1=value1&key3=value3&key2=value2&sig=md5signature 其中最后的 md5signature 是将前面所有内容按 key 的字典序排列,形成 key1=value1key2=value2key3=value3,加上应用的 Secret Key 后的 MD5 加密值。POST 数据前,需要将所有 value 进行 URL Encode(用 curl_easy_escape 即可)。


上面说的很多,现实用的话 HTTP GET 最常用的就是下载。POST 多用在表单的提交(比如登录)。

OK~没啥说了,坚持看到这里的各位辛苦了!

ps.  MD5 加密找到一个不错的库:http://libmd5-rfc.sourceforge.net/

ps2. XML 的话 TinyXML 和 RapidXml 都是不错的库。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter