如何正确地重复使用卷曲手柄

时间:2013-02-16 14:08:47

标签: c curl libcurl handle

我想正确地重复使用curl句柄,这样它就不会给我带来错误和正常运行。

假设我有这段代码:

    CURL *curl;

    curl_global_init(CURL_GLOBAL_ALL);
    curl = curl_easy_init();

    curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0...");
    curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com");
    curl_easy_perform(curl);

    curl_easy_setopt(curl, CURLOPT_URL, "http://www.bbc.com");
    curl_easy_perform(curl);

    curl_easy_cleanup(curl);
    curl_global_cleanup();

这是重用卷毛手柄的好方法吗?或者我需要在该句柄上使用curl_easy_reset()吗?

如果有人建议你应该避免卷曲,我也会感激。也许有人可以给我一个已经存在的信息来源的链接?

3 个答案:

答案 0 :(得分:10)

在easy界面上使用环境libcurl时,首先必须调用:

  • curl_easy_init(),简单易用,
  • curl_global_init(),大多数情况下,flag选项必须为CURL_GLOBAL_ALL

这两个函数中的每一个在开始时只调用一次,需要相反的清理:

  • curl_easy_cleanup()当你完成了你已声明的句柄时,
  • 当你完成了libcurl时,
  • curl_global_cleanup()

为了获得更好的结果,请尽可能多地检查错误。 Libcurl为此提供curl_easy_strerror()功能。它返回一个描述CURLcode错误的字符串。此外,某些函数返回值 如果一切正常,则为CURL_OK或特定的整数。

例如,以下是使用CURLOPT_URL选项的正确方法:

#include <curl.h>

int main(void)
{
    /* declaration of an object CURL */
    CURL *handle;                   

    /* result of the whole process */
    CURLcode result;              

    /* the first functions */
    /* set up the program environment that libcurl needs */
    curl_global_init(CURL_GLOBAL_ALL);
    /* curl_easy_init() returns a CURL easy handle that you're gonna reuse in other easy functions*/
    handle = curl_easy_init();



    /* if everything's all right with the easy handle... */
    if(handle) 
    {
            /* ...you can list the easy functions */
            /* here we just gonna try to get the source code of http://example.com */
            curl_easy_setopt(handle, CURLOPT_URL, "http://example.com");

            /* but in that case we also tell libcurl to follow redirection */
            curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);

            /* perform, then store the expected code in 'result'*/ 
            result = curl_easy_perform(handle);

            /* Check for errors */ 
            if(result != CURLE_OK)
            {
                    /* if errors have occured, tell us wath's wrong with 'result'*/
                    fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(result));

                    return 1;
            }
    }
     /* if something's gone wrong with curl at the beginning, we'll appriciate that piece of code */  
    else 
    {
            fprintf(stderr, "Curl init failed!\n");

            return 1;
    }

    /* cleanup since you've used curl_easy_init */ 
    curl_easy_cleanup(handle);

    /* this function releases resources acquired by curl_global_init() */
    curl_global_cleanup();

    /* make the programme stopping for avoiding the console closing befor you can see anything */
    system("PAUSE");

    return 0;
}

如果您想为完全不同的目的重用该句柄,最好使用不同的CURL 容易处理。 仍然你的代码应该工作正常,但我会使用不同的句柄,因为它显然是两个单独的操作。

但是,有时您需要使用相同的句柄,如果您不想自动重置它,请使用相应的函数:

void curl_easy_reset(CURL *handle); 

请注意,它不会更改实时连接,会话ID缓存,DNS缓存,Cookie和句柄中的共享。

我没有尝试过,但是使用你的代码它应该给我们这样的东西:

#include <curl.h>

int main(void)
{
    CURL *handle;                   
    CURLcode result; 

    int error = 0;
    int error2 = 0;             

    curl_global_init(CURL_GLOBAL_ALL);
    handle = curl_easy_init();

    if(handle) 
    {
            curl_easy_setopt(handle, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2) Gecko/20100115 Firefox/3.6");
            curl_easy_setopt(handle, CURLOPT_URL, "http://www.google.com");
            result = curl_easy_perform(handle);

            if(result != CURLE_OK)
            {
                    fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(result));

                    error++;
            }

            Sleep(5000);         // make a pause if you working on console application

            curl_easy_reset(handle);

            curl_easy_setopt(handle, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2) Gecko/20100115 Firefox/3.6");      // have to write it again
            curl_easy_setopt(handle, CURLOPT_URL, "http://www.bbc.com");
            result = curl_easy_perform(handle);

            if(result != CURLE_OK)
            {
                    fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(result));

                    error2++;
            }

            if(error == 1 || error2 == 1)
            {
                    return 1;
            }
    }
    else 
    {
            fprintf(stderr, "Curl init failed!\n");

            return 1;
    }

    curl_easy_cleanup(handle);
    curl_global_cleanup();

    system("PAUSE");

    return 0;
}

如果您对Sleep有任何疑问,请尝试将其替换为sleep_sleep或将5000替换为5。

答案 1 :(得分:6)

如果我正确理解了这个问题,您想知道是否可以拨打curl_easy_perform(),然后只通过curl_easy_setoption()更改网址然后再拨打电话?这应该没有任何错误,因为该功能不会更改任何先前设置的句柄选项。这是一个简短的工作示例:

size_t writeCallback(char* contents, size_t size, size_t nmemb, std::string* buffer) {
  size_t realsize = size * nmemb;
  if(buffer == NULL) {
    return 0;
  }
  buffer->append(contents, realsize);
  return realsize;  
}

int main(int argc, char** argv) {
  std::string buffer;
  // initialize global
  curl_global_init(CURL_GLOBAL_ALL);
  // start a libcurl easy session
  CURL* ch = curl_easy_init();
  // this options will only be set once 
  curl_easy_setopt(ch, CURLOPT_VERBOSE, 0);
  curl_easy_setopt(ch, CURLOPT_FOLLOWLOCATION, 1);
  curl_easy_setopt(ch, CURLOPT_USERAGENT, "Crawler");
  curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, &writeCallback);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &buffer);

  std::vector<const char*> queue;
  queue.push_back("http://www.google.com");
  queue.push_back("http://www.stackoverflow.com");

  const char* url;
  CURLcode code;

  do {
      // grab an url from the queue
      url = queue.back();
      queue.pop_back();
      // only change this option for the handle
      // the rest will stay intact
      curl_easy_setopt(ch, CURLOPT_URL, url);
      // perform transfer
      code = curl_easy_perform(ch);
      // check if everything went fine
      if(code != CURLE_OK) {

      }
      // clear the buffer
      buffer.clear();
  } while(queue.size() > 0);
  // cleanup
  curl_easy_cleanup(ch);
  curl_global_cleanup();

  return 0;
}
  

或者我是否需要在该句柄上使用curl_easy_reset()?

答案是 ,因为curl_easy_perform()不会重置您的代码应该没有的任何选项,您只需更改网址{{1 }}

答案 2 :(得分:3)

  

或者我是否需要在该句柄上使用curl_easy_reset()?

你要么重置它XOR清理它(再次分配curl_easy_init()的返回值之前) - 两者都不好。有关详细信息,请参阅the documentation