免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123
最近访问板块 发新帖
楼主: 雨过白鹭洲
打印 上一主题 下一主题

源码阅读第二期之curl-7.22.0 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2011-11-09 17:13 |只看该作者
恩,支持段老哥。。
正在看着curl呢

论坛徽章:
0
22 [报告]
发表于 2011-11-11 10:15 |只看该作者
回复 21# linggang_2011


    呵呵,最近比较懒,都没怎么分析这个代码

论坛徽章:
0
23 [报告]
发表于 2011-11-11 10:17 |只看该作者
本帖最后由 duanjigang 于 2011-11-11 10:23 编辑

尝试从 curl 的 main 函数去分析处理流程,后来发现楼主写的已经比较细了,因此我就从别的角度做些分析吧。
想起来我以前做过的基于 libcurl 的应用,看了下 curl 的 main 函数,发现流程主题上是一样的。
都是基于 libcurl 的框架实现的,下面看看基于 libcurl 开发的一般流程。

有些库,自身实现的很复杂,但是它用起来却很简单,而且会把调用的流程规定的很死。libcurl 就是其中一款。比如我们以前公司搞开发的一般流程是



  1. 初始化


  2. while (结束条件未到)
  3. {
  4.    执行任务
  5. }

  6. 释放资源
  7. 退出
复制代码
大概所有程序都是这样的流程吧。基于 libcurl 的应用大概流程是这样的


  1. //初始化
  2. curl_global_init();
  3. curl = curl_easy_init();

  4. //设置参数
  5. curl_easy_setopt(...)//一堆setopt
  6. //目的就是设置URL参数,处理函数,等等参数。

  7. //执行任务
  8. res = curl_easy_perform(curl);

  9. //释放资源

  10. curl_easy_cleanup(curl);
复制代码
http://curl.haxx.se/libcurl/c/ftpget.html
这里有N多例子都是这样处理的

论坛徽章:
0
24 [报告]
发表于 2011-11-11 10:40 |只看该作者
看一个最简单的例子,是如何按照这个流程走的:

  1. /***************************************************************************
  2. *                                  _   _ ____  _
  3. *  Project                     ___| | | |  _ \| |
  4. *                             / __| | | | |_) | |
  5. *                            | (__| |_| |  _ <| |___
  6. *                             \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at http://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. ***************************************************************************/
  22. #include <stdio.h>

  23. #include <curl/curl.h>

  24. /*
  25. * This is an example showing how to get a single file from an FTP server.
  26. * It delays the actual destination file creation until the first write
  27. * callback so that it won't create an empty file in case the remote file
  28. * doesn't exist or something else fails.
  29. */

  30. struct FtpFile {
  31.   const char *filename;
  32.   FILE *stream;
  33. };

  34. static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
  35. {
  36.   struct FtpFile *out=(struct FtpFile *)stream;
  37.   if(out && !out->stream) {
  38.     /* open file for writing */
  39.     out->stream=fopen(out->filename, "wb");
  40.     if(!out->stream)
  41.       return -1; /* failure, can't open file to write */
  42.   }
  43.   return fwrite(buffer, size, nmemb, out->stream);
  44. }


  45. int main(void)
  46. {
  47.   CURL *curl;
  48.   CURLcode res;
  49.   struct FtpFile ftpfile={
  50.     "curl.tar.gz", /* name to store the file as if succesful */
  51.     NULL
  52.   };

  53.   curl_global_init(CURL_GLOBAL_DEFAULT);

  54.   curl = curl_easy_init();
  55.   if(curl) {
  56.     /*
  57.      * You better replace the URL with one that works!
  58.      */
  59.     curl_easy_setopt(curl, CURLOPT_URL,
  60.                      "ftp://ftp.example.com/pub/www/utilities/curl/curl-7.9.2.tar.gz");
  61.     /* Define our callback to get called when there's data to be written */
  62.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
  63.     /* Set a pointer to our struct to pass to the callback */
  64.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);

  65.     /* Switch on full protocol/debug output */
  66.     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

  67.     res = curl_easy_perform(curl);

  68.     /* always cleanup */
  69.     curl_easy_cleanup(curl);

  70.     if(CURLE_OK != res) {
  71.       /* we failed */
  72.       fprintf(stderr, "curl told us %d\n", res);
  73.     }
  74.   }

  75.   if(ftpfile.stream)
  76.     fclose(ftpfile.stream); /* close the local file */

  77.   curl_global_cleanup();

  78.   return 0;
  79. }

复制代码

论坛徽章:
0
25 [报告]
发表于 2011-11-11 10:53 |只看该作者
对这个例子做个简单的注解,就很明白了。

  1. Download ftpget.c

  2. /***************************************************************************
  3. *                                  _   _ ____  _
  4. *  Project                     ___| | | |  _ \| |
  5. *                             / __| | | | |_) | |
  6. *                            | (__| |_| |  _ <| |___
  7. *                             \___|\___/|_| \_\_____|
  8. *
  9. * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
  10. *
  11. * This software is licensed as described in the file COPYING, which
  12. * you should have received as part of this distribution. The terms
  13. * are also available at http://curl.haxx.se/docs/copyright.html.
  14. *
  15. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  16. * copies of the Software, and permit persons to whom the Software is
  17. * furnished to do so, under the terms of the COPYING file.
  18. *
  19. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  20. * KIND, either express or implied.
  21. *
  22. ***************************************************************************/
  23. #include <stdio.h>

  24. #include <curl/curl.h>

  25. /*
  26. * This is an example showing how to get a single file from an FTP server.
  27. * It delays the actual destination file creation until the first write
  28. * callback so that it won't create an empty file in case the remote file
  29. * doesn't exist or something else fails.
  30. */

  31. //结构体,用来存储当前应用的私有数据,这个数据结构会被存储在该应用对应的会话流中
  32. struct FtpFile
  33. {
  34.         const char *filename;
  35.         FILE *stream;
  36. };
  37. //写回调函数,当ftp 数据到来时,curl 会调用 开发者初始化时传入的这个回调函数进行数据处理
  38. static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
  39. {
  40.         //首先从流中拿出来我们自己定义得私有数据
  41.         struct FtpFile *out=(struct FtpFile *)stream;
  42.         //如果是第一次调用(文件还没创建),创建文件
  43.         if(out && !out->stream) {
  44.                 /* open file for writing */
  45.                 out->stream=fopen(out->filename, "wb");
  46.                 if(!out->stream)
  47.                         return -1; /* failure, can't open file to write */
  48.         }
  49.         //不是第一次调用,直接写入数据就行了
  50.         return fwrite(buffer, size, nmemb, out->stream);
  51. }


  52. int main(void)
  53. {
  54.         CURL *curl;
  55.         CURLcode res;
  56.         //私有数据结构初始化,文件名称和文件指针
  57.         struct FtpFile ftpfile={
  58.                 "curl.tar.gz", /* name to store the file as if succesful */
  59.                         NULL
  60.         };
  61.        
  62.         //初始化部分
  63.         curl_global_init(CURL_GLOBAL_DEFAULT);
  64.         //获取句柄
  65.         curl = curl_easy_init();
  66.        
  67.         //下面是参数设置过程
  68.         if(curl) {
  69.     /*
  70.         * You better replace the URL with one that works!
  71.                 */
  72.                 //设置 URL 参数
  73.                 curl_easy_setopt(curl, CURLOPT_URL,
  74.                         "ftp://ftp.example.com/pub/www/utilities/curl/curl-7.9.2.tar.gz");
  75.                 /* Define our callback to get called when there's data to be written */
  76.                 //设置写回调函数
  77.                 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
  78.                 /* Set a pointer to our struct to pass to the callback */
  79.                 //设置私有数据,ftpfile 这个结构会被存储到 curl 对应的流中,方便我们在回调函数中使用
  80.                 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
  81.                
  82.                 /* Switch on full protocol/debug output */
  83.                 //打印信息
  84.                 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
  85.                
  86.                 //执行任务
  87.                 res = curl_easy_perform(curl);
  88.                
  89.                 /* always cleanup */
  90.                 //释放资源
  91.                 curl_easy_cleanup(curl);
  92.                
  93.                 if(CURLE_OK != res) {
  94.                         /* we failed */
  95.                         fprintf(stderr, "curl told us %d\n", res);
  96.                 }
  97.         }
  98.         //关闭文件
  99.         if(ftpfile.stream)
  100.                 fclose(ftpfile.stream); /* close the local file */
  101.         //全局释放资源
  102.         curl_global_cleanup();
  103.        
  104.         return 0;
  105. }
复制代码

论坛徽章:
0
26 [报告]
发表于 2011-11-11 11:05 |只看该作者
本帖最后由 duanjigang 于 2011-11-11 11:08 编辑

然后来看看 curl 的 初始化 设置参数, 执行任务, 释放资源都是在哪里?


首先,是在 main 函数的 main_init 中调用了 global_init 函数:

  1. ///////main 函数
  2. if(main_init() != CURLE_OK) {
  3.     helpf(config->errors, "error initializing curl library\n");
  4.     return CURLE_FAILED_INIT;
  5.   }
  6. 。。。。。。。。。。。。

  7. static CURLcode main_init(void)
  8. {
  9. #ifdef DJGPP
  10.   /* stop stat() wasting time */
  11.   _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
  12. #endif

  13.   return curl_global_init(CURL_GLOBAL_DEFAULT);
  14. }
复制代码
在 main_init 调用之后,紧接着就是 easy_init 的调用:

  1. curl = curl_easy_init();
  2.   if(!curl) {
  3.     clean_getout(config);
  4.     return CURLE_FAILED_INIT;
  5.   }
复制代码

论坛徽章:
0
27 [报告]
发表于 2011-11-11 11:13 |只看该作者
本帖最后由 duanjigang 于 2011-11-11 11:18 编辑

然后从 src/main.c 的 5264 行开始 到 5640 这 近乎 400行的代码都是在做 设置参数的工作
当然
my_setopt_str 和 my_setopt 也被调用的淋漓尽致
(注意 curl_easy_setopt 是 通过 my_setopt 函数族实现的)

  1. my_setopt(curl, CURLOPT_READDATA, &input);
  2.         /* what call to read */
  3. ..................

  4. /* new in 7.22.0 */
  5.         if(config->gssapi_delegation)
  6.           my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
  7.                         config->gssapi_delegation);
复制代码
紧接着,是执行任务函数,通过 perform 函数来体现

  1.   for(;;) {
  2.           res = curl_easy_perform(curl);
  3.           if(!curl_slist_append(easycode, "ret = curl_easy_perform(hnd);")) {
  4.             res = CURLE_OUT_OF_MEMORY;
  5.             break;
  6.           }
复制代码
最后一行,main_free 完成释放工作。

  1. main_free(); /* cleanup */

复制代码

论坛徽章:
0
28 [报告]
发表于 2011-12-02 14:53 |只看该作者
请问,libcurl的续传中支持http上传续传吗?

论坛徽章:
0
29 [报告]
发表于 2014-03-21 16:04 |只看该作者
本帖最后由 yiqingfeng0215 于 2014-03-21 16:05 编辑

呵呵,终于找到高人了,一定要请教下
遇到个问题,一个网站,返回的头文件有多个set-cookie,例如

header("Set-Cookie:test=sid;domain=; path=/");
header("Set-Cookie:test2=sid;domain=; path=/");


我在自己的电脑上用php的curl,想模拟登录这个网站,但curl返回的信息中,test这个cookie消失了,只有test2这个cookie,请问该如何处理啊?
curl有办法取得这两个cookie吗?我测试了一下,也只能获得test2这个cookie

论坛徽章:
0
30 [报告]
发表于 2014-03-27 22:41 |只看该作者
C下面我使用的libcurl里有可以把接收到的cookie信息保存到文件里,下次在发送请求时,可以在使用这个cookie文件

curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookie_file.txt");  这是设置提交保存的cookie文件

curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookie_file.txt");  这是设置保存cookie的文件

回复 29# yiqingfeng0215


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP