#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), таким образом пропуская цикл уничтожения дескриптора и запрашивая новый!