【问题标题】:how to properly reuse a curl handle如何正确重用卷曲手柄
【发布时间】:2013-02-01 09:35:03
【问题描述】:

我想正确地重用 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()

如果有人建议您在 curl 中应避免做什么,我将不胜感激。也许有人可以给我一个已经存在的信息源的链接?

【问题讨论】:

    标签: c curl libcurl handle


    【解决方案1】:

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

    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();
      if (ch) {
        // Something went wrong
        curl_global_cleanup();
        return -1;
      }
    
      // These 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);
    
      // Push a couple of URLs onto queue.
      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 the CURLOPT_URL 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) {
            // Handle any errors.
          }
    
          // 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() 不会重置您的代码应该没问题的任何选项,您可以坚持只更改 URL,例如 curl_easy_setoption(curl, CURLOPT_URL, &lt;newurl&gt;);

    【讨论】:

      【解决方案2】:

      在easy界面使用环境libcurl时,首先要调用:

      • curl_easy_init(),它初始化了简单的句柄,
      • curl_global_init(),大多数情况下标志选项必须是CURL_GLOBAL_ALL

      这两个函数中的每一个在开始时只被调用一次,并且需要对其进行相反的清理:

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

      为了获得更好的结果,请尽可能多地检查错误。 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。

      【讨论】:

        【解决方案3】:

        或者我需要在那个句柄上使用 curl_easy_reset() 吗?

        您要么重置它 XOR 清理它(在再次分配 curl_easy_init() 的返回值之前) - 两者都做不好。如需更多信息,请参阅the documentation

        【讨论】:

        • 如果要再次使用,请使用 curl_easy_reset(),否则使用 curl_easy_cleanup() 并停止使用。
        【解决方案4】:

        我通常在每次请求后使用我的 curl 句柄调用 curl_easy_reset,这允许我通过获取新的 curl 句柄 (curl_easy_init) 获得的默认选项重新使用句柄,从而跳过循环破坏手柄并要求一个新的!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-12-01
          • 2014-10-09
          • 2013-10-12
          • 2010-12-17
          • 2017-04-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多