libcurl C : длительная задержка ответа от сервера

#c #curl #networking #https #libcurl

Вопрос:

У меня есть libcurl запущенная программа Ubuntu 20.04.1 LTS , которая загружает данные веб-страницы, когда обнаруживает, что веб HTTPS status code -страница меняется с 503 на 200 . Когда код меняется, это означает, что владельцы сайта загрузили на страницу новую информацию.

Раньше я мог обнаруживать изменение от 503 до 200 примерно за 150-200 миллисекунд последовательно в течение нескольких месяцев.

Однако примерно с середины июля 2021 года (и без каких-либо изменений кода libcurl программы), когда сайт меняется с 503 200 «на», я не получаю ответа в течение от 7 до 18 секунд, чтобы сообщить мне, что код изменился.

Примечание: Я поговорил с другими пользователями, которые подтвердили, что они все еще получают обновленные данные за менее чем 200 миллисекунд, а также с владельцами сайтов, которые описали все как работающее в обычном режиме.

Текущий выход/ попытки решить:

  1. Удален и переустановлен libcurl с sudo apt-get install libcurl4-openssl-dev
  2. Я решил использовать Wireshark , результат которого можно увидеть здесь [используйте код 173967, если требуется/ с удовольствием сделаю это]. Запланированное изменение status code обычно происходит в/после 1633012200 . libcurl IP-адрес отправки отображается как 192.168.0.29 и адрес назначения 13.224.247.34 , но я не могу определить, действительно ли информация доставляется вовремя, и мое приложение вызывает узкое место, или существует реальная проблема с сетью.
  3. Используется отладка инструкций печати. Одна инструкция печатается "sent" при отправке запроса кода ответа, а другая печатается "received" с возвращенным кодом ответа и an EPOCH timestamp . На обратном отсчете времени до запланированного изменения веб-сайта с 503 на 200 , в терминале я вижу ожидаемый результат sent -> received -> EPOCH timestamp . Когда происходит запланированное изменение веб-сайта 503 200 с на, все , что я вижу в терминале sent , — это задержка от 7 до 18 секунд перед выводом received 200 -> timestamp .
  4. Протестировал один и тот же код с одним и тем же URL-адресом на трех отдельных серверах с разными IP addresses , но с одной и той же операционной системой, которые все дали один и тот же отложенный результат, хотя некоторые немного менее медленные, чем другие.

An example of print statement output:

 /*
listening...

sent
response
503
1632925797111

sent
response
503
1632925797227

sent
response
503
1632925797336

sent
    <---- Program hangs here for approx. 7-18 seconds before printing 200 and timestamp*/
 

Current code:

 #include <iomanip>
#include <vector>
#include <iostream>
#include <string>
#include <chrono>
#include <future>
#include <algorithm>
#include <cstring>

#include <curl/curl.h>

// Function for writing callback
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) {

        std::vector<char> *response = reinterpret_cast<std::vector<char> *>(userdata);
        response->insert(response->end(), ptr, ptr nmemb);
        return nmemb;
}

// Handle requests to URL
long request(CURL *curl, const std::string amp;url) {

        std::vector<char> response;
        long response_code;

        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);

        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, amp;response);

        curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
        curl_easy_setopt(curl, CURLOPT_COOKIE, "");

        auto res = curl_easy_perform(curl);

        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, amp;response_code);


        if (response_code == 200) {
            // do something
        }
        return response_code;
}

int main() {

    curl_global_init(CURL_GLOBAL_ALL);
    CURL *curl = curl_easy_init();

    std::string value1;
    std::cout << std::endl << "Press 1 to start listening..." << std::endl;
    std::cin >> value1;

    if (value1 == "1") {

        std::cout << std::endl << "listening..." << std::endl;

        while (true) {
            std::cout << "sent" << std::endl;
            long response_code = request(curl, "https://someurl.xyz");
            std::cout << "response" << std::endl;
            if (response_code == 200) {

                std::int64_t epoch_2 = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
                std::cout << "code 200 detected at : " << epoch_2 << std::endl;
                break; // Page updated
            }
            else {
                std::cout << response_code << std::endl;
                            std::int64_t epoch_3 = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
                            std::cout << epoch_3 << std::endl;
            }
        }
    }
    curl_easy_cleanup(curl);
    curl_global_cleanup();

    return 0;
}
 

Краткий вопрос:

Q1. Учитывая, что другие пользователи не испытывают этого, и я провел этот же тест на разных серверах с разными IP-адресами, знает ли кто-нибудь, что может вызвать задержку моей программы, обнаруживающей изменение кода состояния? Как уже говорилось ранее, эта программа работала, как и ожидалось, практически без задержек до июля 2021 года.

Этот вопрос решается уже более трех месяцев. Если у кого-нибудь есть какие-либо идеи или, возможно, они могли бы указать мне направление для диагностики этого, я был бы очень признателен.

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

1. Есть ли какие-либо задействованные доверенные лица? Вы можете попробовать добавить некоторые случайные данные в URL: https://someurl.xyz?foo=1323453545 (и каждый раз указывать другое число). Это может обмануть прокси-серверы, чтобы они не отправляли вам кэшированную страницу.

2. Да, похоже, это может сработать. Прокси-сервер кэширования может принять решение не выполнять выборку страниц для всех запросов. Вместо этого он хранит страницы в течение некоторого времени и просто отправляет сохраненные страницы для экономии пропускной способности, что означает, что вы не увидите обновлений на этой странице, даже если она была обновлена. Добавляя случайные данные в запрос, иногда можно обойти это поведение. На самом деле это не обязательно должно быть случайным. Вы могли бы просто иметь счетчик, который вы увеличиваете для каждого отправляемого запроса.

3. Отлично! Надеюсь, это так просто. Причина: Возможно, кто-то включил кэширование на корпоративном прокси-сервере.

4. О… да, есть много неприятных вещей вне контроля приложения, которые могут изменить поведение. Если сайт изменил свой IP-номер, но у него было действительно много времени, чтобы жить в записи DNS, это может привести к тому, что ваши пакеты, например, перейдут на неправильный IP-номер. Это, вероятно, не проявилось бы так, но это также вызвало бы путаницу. Плохие таблицы маршрутизации также могут все испортить. У меня была плохая маршрутизация, когда мои пакеты внезапно поворачивали через Атлантику и обратно. Я ничего не мог сделать, кроме как упомянуть об этом своему интернет-провайдеру: -)

5. Да — это полностью испортило мою игру 🙂 Не за что! Вы также можете попытаться выяснить, где это занимает время, запустив программу трассировки в течение некоторого времени. ПингПлоттер популярен, но является коммерческим (но первые 14 дней бесплатны, я только что прочитал — я не связан с ними).