как правильно повторно использовать дескриптор curl

#c #libcurl

Вопрос:

Я хочу правильно повторно использовать дескриптор 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? Или мне нужно использовать curl_easy_reset() этот дескриптор?

Я также был бы признателен, если бы кто-нибудь подсказал, чего вам следует избегать в curl. Может быть, кто-нибудь может дать мне ссылку на уже существующий источник информации?

Ответ №1:

Если я правильно понимаю вопрос, вы хотели бы знать, можете ли вы выполнить вызов curl_easy_perform() , а затем только изменить URL 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, amp;writeCallback);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, amp;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() not сбросит какие-либо параметры, ваш код должен быть в порядке, и вы можете придерживаться только изменения URL, например curl_easy_setoption(curl, CURLOPT_URL, <newurl>); .

Ответ №2:

При использовании среды libcurl в интерфейсе easy сначала необходимо вызвать :

  • 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 resu<              

    /* 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: %sn", 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); 
 

Обратите внимание, что это не изменяет текущие соединения, кэш идентификаторов сеанса, кэш DNS, файлы cookie и общие ресурсы из дескриптора.

Я не пробовал, но с вашим кодом это должно дать нам что-то вроде этого :

 #include <curl.h>

int main(void)
{
    CURL *handle;                   
    CURLcode resu< 

    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: %sn", 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: %sn", 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() для этого дескриптора?

Вы либо сбрасываете его, либо очищаете (перед повторным присвоением возвращаемого значения curl_easy_init() ) — делать и то, и другое нехорошо. Для получения дополнительной информации см. Документацию.

Комментарии:

1. Используйте curl_easy_reset(), если вы хотите использовать его снова, в противном случае используйте curl_easy_cleanup() и прекратите его использование.

Ответ №4:

Я обычно вызываю curl_easy_reset с моим дескриптором curl после каждого запроса, это позволяет мне повторно использовать дескриптор с параметрами по умолчанию, которые вы получите, получив новый дескриптор curl (curl_easy_init), таким образом пропуская цикл уничтожения дескриптора и запрашивая новый!