Я использую Ubuntu 22.04 и libcurl 7.81.0 для создания и отправки команды onvif post. Изначально у меня все работало на Python, но я не могу использовать Python в окончательном проекте. Поэтому я хотел бы воспроизвести команду в libcurl. Моя проблема не в отправке команд и получении ответов.
Мне нужно больше ясности относительно того, как установить URI запроса в заголовке. Когда я отправляю команду публикации через Python с помощью Zeep, заголовок сообщения выглядит следующим образом на изображении из Wireshark:
Однако, когда я пытаюсь отправить сообщение внутри libcurl, я получаю следующее:
Есть ли опция Curlop, которую мне не хватает, чтобы установить это поле URI? Мне действительно нужен Curl, чтобы точно воспроизвести то, что было отправлено в Python.
Мои параметры завитка установлены с помощью:
curl = curl_easy_init();
std::string url = serverIP + ":" + std::to_string(serverPort);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, settings.responseTimeout_ms);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &cameraResponse);
Мой обратный вызов просто:
size_t writeCallback(char* contents, size_t size, size_t nmemb, std::string* userp)
{
userp->append(contents, size * nmemb);
return size * nmemb;
}
Затем я создаю и устанавливаю поле заголовка (опуская фактическое содержимое строки из этого сообщения).
struct curl_slist* header = nullptr;
header = curl_slist_append(header, host.c_str());
header = curl_slist_append(header, agent.c_str());
header = curl_slist_append(header, acceptEncoding.c_str());
header = curl_slist_append(header, accept.c_str());
header = curl_slist_append(header, connection.c_str());
header = curl_slist_append(header, soapAction.c_str());
header = curl_slist_append(header, contentType.c_str());
header = curl_slist_append(header, contentLength.c_str());
контент представляет собой просто закодированные данные в формате мыла, которые я хочу отправить. Насколько я знаю, здесь тоже нет проблем.
Затем я устанавливаю последние параметры завитка и вызываю easy Perform
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, content.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
CURLcode curlResult = curl_easy_perform(curl);
Я обнаружил, что ответы с моей камеры при использовании libcurl примерно в 2 раза медленнее, чем при использовании Python. Я предполагаю, что это связано с различиями в формате сообщения. Я хотел бы начать с исправления запроса URI, как упоминалось выше. Буду признателен за отзывы по этой теме.
Я использую это выше, чтобы установить IP-адрес и порт камеры. Добавляю ли я информацию URI в конец или вместо того, что я сделал?
Ваш обратный вызов должен принимать void*
, а не std::string*
, и вам следует сделать static_cast<std::string*>(userp);
, чтобы получить std::string*
. Это может работать так же, как вы, но его поведение неопределенно.
Попробуйте добавить путь и посмотрите, что произойдет.
URL-адрес content
закодирован?
Это нормально и легко измениться. была моей первоначальной функцией, но я провел немало экспериментов. Мой вопрос был более конкретным для поля URI, которое, я думаю, @n.m. может быть, ИИ тоже ускользнул. Я просто имею привычку размещать код в сообщениях, так как его, скорее всего, попросят.
контент — это сообщение onvif в формате мыла.
Есть ли опция Curlop, которую мне не хватает, чтобы установить это поле URI?
Вы уже используете его — CURLOPT_URL. Вам просто нужно указать полный URL-адрес HTTP, а не только IP-адрес и порт сервера:
Передайте указатель на URL-адрес для работы. Параметр должен быть символом * в виде строки с нулевым символом в конце, которая должна быть закодирована в URL-адресе в следующем формате:
схема://хост:порт/путь
Попробуй это:
std::string url = "http://" + serverIP + ":" + std::to_string(serverPort) + "/onvif/DeviceIO";
// or "https://" if needed ...
Если serverPort
— это стандартное значение 80 для URL-адреса HTTP или 443 для URL-адреса HTTPS, вы можете просто его полностью опустить:
std::string url = "http://" + serverIP + "/onvif/DeviceIO";
// or "https://" if needed ...
Примечание: при использовании CURLOPT_HTTPHEADER вам не нужно самостоятельно отправлять заголовок Host
, пусть libcurl сделает это за вас на основе указанного вами URL-адреса. Кроме того, некоторые другие заголовки, которые вы отправляете вручную, можно обрабатывать с помощью других параметров libcurl, таких как CURLOPT_ACCEPT_ENCODING , CURLOPT_USERAGENT , CURLOPT_POSTFIELDSIZE и т. д.
Спасибо. Это было полезно и дало мне именно то, что я искал. н.м. Возможно, ИИ также дал ответ, но я ценю полное объяснение. Моя проблема заключалась в том, что я не полностью понимал libcurl. Я также ценю другие указанные области. Я обновил свое приложение соответствующим образом.
Вариант, который вы ищете, — это сюрприз-сюрприз CURLOPT_URL. (URL — это разновидность URI)