Как определить латентность удаленного сервера через браузер

Я запускаю пару серверов туннелирования игр и хотел бы иметь страницу, на которой клиент может запустить пинг на всех серверах и выяснить, какой из них наиболее отзывчив. Насколько я вижу, кажется, что нет правильного способа сделать это в JavaScript, но я подумал, может быть, кто-нибудь знает способ сделать это во флэш-памяти или какой-либо другой технологии клиентского браузера?


person Mladen Mihajlovic    schedule 02.02.2009    source источник
comment
Меня очень интересует ваше решение. Есть ли шанс получить какие-то результаты? Заранее спасибо !   -  person Theo.T    schedule 23.03.2009
comment
Самый интересный ответ мне дал Элирам (stackoverflow.com/questions/503199/), но StackOverflow уже выбрал ответ за меня. Однако я не стал продвигать этот проект дальше. Я не флеш-разработчик   -  person Mladen Mihajlovic    schedule 23.03.2009


Ответы (9)


Большинство технологий апплетов, включая Javascript, применяют политику одного и того же происхождения. Возможно динамическое добавление элементов DOM, таких как изображения, и сбор информации о времени с помощью обработчика событий onload.

Псевдокод

for (server in servers) {
  var img = document.createElement('IMG');
  server.startTime = getCurrentTimeInMS();
  img.onload=function() { server.endTime = getcurrentTimeInMS(); }
  img.src = server.imgUrl;
}

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

Недостатки:

  • Вероятно, вы используете неправильный инструмент для работы. Браузер не приспособлен для такого рода приложений.
  • Наверное, это совсем неточно.
  • Если ресурс, который вы запрашиваете, кэшируется, он не даст вам желаемых результатов, но вы можете обойти это, каждый раз меняя URL-адрес.
  • Это интенсивно использует полосу пропускания по сравнению с обычным пингом. Сделайте изображение крошечным, например, файл spacer.gif.
  • Время зависит не только от задержки удаленного сервера, но и от пропускной способности этого сервера. Это может быть более или менее полезной мерой, но важно отметить, что это не просто задержка.
  • Вы должны иметь возможность обслуживать HTTP-запросы с разных серверов, и, что особенно важно, каждый сервер должен обслуживать один и тот же ресурс (или ресурс одинаковой длины). Условия на сервере могут повлиять на время отклика, например, если один сервер сжимает данные, а другой нет.
person Mr. Shiny and New 安宇    schedule 18.02.2009
comment
Используйте new Image() вместо создания целого DOM-объекта. - person Georg Schölly; 22.02.2009
comment
@gs: Есть ли преимущество в использовании нового изображения ()? - person Mr. Shiny and New 安宇; 23.02.2009
comment
Проблема со всеми этими решениями, которые включают загрузку чего-либо, заключается в том, что они действительно проверяют скорость веб-сервера, а не задержку сетевого соединения. Так что это не совсем верное отражение, особенно для моих нужд, которые связаны с очень специфическими скоростями задержки сети. - person Mladen Mihajlovic; 23.03.2009
comment
@Mladen Mihajlovic: Это ограничение используемой вами технологии. Большинство технологий апплетов не позволяют вам устанавливать произвольные соединения TCP/UDP с произвольными серверами. Это то, что вам нужно. - person Mr. Shiny and New 安宇; 23.03.2009
comment
Кажется, во Flash это возможно (см. ответ ниже). Единственная проблема в том, что я вообще не знаю flash :) - person Mladen Mihajlovic; 25.03.2009

Перед обращением к серверу запишите время Javascript:

var startTime = new Date();

Загрузите изображение с сервера:

var img = new Image()
img.onload = function() {
    // record end time
}
img.src = "http://server1.domain.com/ping.jpg";

Как только запрос будет выполнен, снова запишите время. (Учитывая, конечно, что время ожидания запроса не истекло.)

var endTime = new Date();

Ваш пинг в миллисекундах:

var ping = endTime. getTime() - startTime.getTime();
person Georg Schölly    schedule 21.02.2009

Все, что вам действительно нужно, это время от начала соединения до момента первого изменения состояния готовности...

function getPing() {
  var start;
  var client = getClient(); // xmlhttprequest object
  client.onreadystatechange = function() {
    if (client.readyState > 0) {
      pingDone(start); //handle ping
      client.onreadystatechange = null; //remove handler
    } 
  }

  start = new Date();
  client.open("HEAD", "/ping.txt"); //static file
  client.send();
}

function pingDone(start) {
  done = new Date();
  ms = done.valueOf() - start.valueOf();
  alert(ms + "ms ping time");
}

function getClient() {
  if (window.XMLHttpRequest)
    return new XMLHttpRequest();

  if (window.ActiveXObject)
    return new ActiveXObject('MSXML2.XMLHTTP.3.0');

  throw("No XMLHttpRequest Object Available.");
}
person Tracker1    schedule 21.02.2009
comment
Это будет работать только в том случае, если вы пингуете сервер, на котором размещена веб-страница, а не для пинга других серверов. - person Mr. Shiny and New 安宇; 24.02.2009

Вот <iframe> подход:


(источник: magnetiq.com)

Создайте таблицу (не обязательно в буквальном <table> смысле) с двумя столбцами. В первом столбце будут указаны имена серверов (и, возможно, ссылки на них). Во втором столбце есть фреймы, которые загружают тестовые документы с соответствующих серверов. Каждый тестовый документ делает это при первоначальном запросе на выборку:

  1. Получить текущее системное время
  2. Выполните перенаправление (302) на второй тестовый документ, передав системное время в качестве параметра запроса.
  3. Второй зондирующий документ считывает текущее системное время, вычисляет дельту от начального показания, которое было передано ему, и просто отображает ее большими жирными буквами. Эта дельта будет временем, которое потребовалось серверу, чтобы ответить клиенту ответом перенаправления, плюс время, которое потребовалось клиенту, чтобы сделать второй запрос к цели перенаправления. Это не совсем «пинг», но это сопоставимая мера относительной задержки клиента с каждым сервером. По сути, это «обратный пинг» от сервера к клиенту.

Вы бы использовали iframe, не нарушая политику того же домена, потому что вообще не было попыток манипулировать содержимым iframe. Игрок просто увидит значения своими глазами, а вы будете полагаться на то, что пользователь взглянет на числа и нажмет на ссылку сервера, которая имеет больше смысла.

person Ates Goral    schedule 24.02.2009

Все, что делает HTTP-запрос (как и большинство ответов здесь), обычно измеряет задержку, которая как минимум вдвое превышает то, что вы видите для обычного пинга, потому что вам понадобится как минимум трехстороннее рукопожатие и пакет завершения ( две поездки туда и обратно, а не одна). Если вы делаете HTTP-запросы, постарайтесь свести заголовки к минимуму. Достаточно длинный заголовок (из-за болтливого сервера или файлов cookie и т. д. на клиенте) может добавить в смесь дополнительные циклы обработки, отбрасывая ваши измерения.

Как указывает Черона, если у вас уже есть активное соединение HTTP 2 с сервером или если сервер использует HTTP 3, это может быть не так.

Наиболее точным вариантом было бы открыть подключение через веб-сокет к каждому серверу и измерить время, необходимое для отправки крошечного сообщения и получения крошечного ответа (после того, как соединение было установлено).

person Peter Burns    schedule 25.02.2009
comment
Это неверно для HTTP2 и HTTP3 - person Cherona; 30.06.2020
comment
Хорошая точка зрения! Отредактировано, чтобы добавить упоминание о HTTP 2, HTTP 3 и веб-сокетах. - person Peter Burns; 31.07.2020

Если вы говорите о запуске чего-то на стороне клиента, я не уверен, что это возможно из-за соображений безопасности.

Возможно, вам лучше всего подойдет java-апплет, но, опять же, его необходимо проверить на соответствие локальной политике безопасности.

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

person Yuval Adam    schedule 02.02.2009
comment
Я знаю, что один из способов сделать это — отправить запрос HEAD, но я больше надеялся, что есть способ сделать это с помощью flash? - person Mladen Mihajlovic; 06.02.2009
comment
Java-апплетам разрешается связываться только с исходным сервером. - person Magnar; 18.02.2009
comment
Апплеты с более либеральной безопасностью разрешены, если они подписаны и приняты. Или, по крайней мере, они были раньше. В последний раз я видел его с Netscape 4. - person Zan Lynx; 25.02.2009

Не так сложно измерить время отклика сервера во Flash.

Flash должен запросить файл политики перед доступом к удаленным серверам. По умолчанию такой файл политики расположен в корневой папке сервера: /crossdomain.xml.

(Вы можете легко найти информацию о формате междоменного файла)

Поскольку такой файл все равно нужен, почему бы не использовать его для измерения времени отклика сервера? Загрузите сам файл вместо изображения и измерьте время, которое потребовалось, с помощью getTimer() .

Это даст вам хорошую оценку HTTP-соединений.

Но если вы имеете дело с игровыми серверами, вы можете напрямую проверить скорость TCP-соединения. Для этого вам потребуется использовать flash.net.Socket. Вам также потребуется сначала запросить файл политики, запустив: Security.loadPolicyFile("xmlsocket://server.domain.com:5342");

Где 5342 представляет собой номер порта вашего сервера, на который он должен ответить соответствующей строкой политики XML. После подключения к сокету любой запрос/ответ позволит вам измерить разное время ответа сервера.

person Eliram    schedule 22.02.2009
comment
Это звучит весьма многообещающе. У вас есть код или пример флеш-апплета, который я вижу? Я сам не программист actionscript. - person Mladen Mihajlovic; 23.02.2009

Проблема с «пингованием файлов» заключается в том, что вы будете оценивать ответ http-сервера, тогда как ваш целевой ресурс для игр, которые вы обслуживаете, может иметь совершенно другое поведение и, следовательно, другую задержку.

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

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

person Theo.T    schedule 21.02.2009

Судя по ответам @Mr. Shiny и @Georg Schölly, полный и прокомментированный пример.

Чтобы протестировать, просто скопируйте и вставьте приведенные ниже коды в том же порядке в пустой файл .html, .php или другой совместимый файл.

Перед началом получения запишите текущее время Javascript. Используя new Date(), мы создаем новый объект даты с текущей датой и временем.

<script type="text/javascript">

var startTime = new Date();

Теперь давайте создадим изображение объекта html, еще без исходного кода, и атрибутируем его переменной img.

var img = new Image();

Следующим спецом ставится источник изображения. .src отражает атрибут src html. Важный! Укажите в img.src очень маленький и легкий файл изображения, если возможно, менее 10 КБ.

Для предотвращения кеша в конец файла после расширения .png был добавлен случайный параметр.

var random_string = Math.random().toString();
img.src = "http://static.bbci.co.uk/frameworks/barlesque/5.0.0/orb/4/img/bbc-blocks-dark.png" + "?" + random_string;

Теперь мы можем вызвать нашу функцию, которая запустится сразу после загрузки изображения, потому что .onload:

img.onload = function() {
    var endTime = new Date();
    var ping = endTime. getTime() - startTime.getTime();
    alert(img.src + " loaded in " + ping + " ms");
}
</script>

Внутри функции у нас есть переменная endTime, которая получает дату и время после загрузки исходного изображения.

Наконец, переменная ping получает начальное время минус конечное время. Всплывающее окно с предупреждением показывает результат.

person Fellipe Sanches    schedule 29.03.2019