Вам приходилось когда-либо писать клиент-серверные приложения? Если да, то, вероятно, вы сталкивались с необходимостью получения времени ответа сервера. Такая необходимость может быть вызвана, например, при работе клиента с сетью серверов, имеющих разное географическое положение, для выбора оптимального сервера. В этом небольшом рецепте показан пример реализации функции получения среднего времени ответа сервера с помощью системной утилиты ping.
Прежде, чем писать код, следует уточнить, что аргументы утилиты ping различаются для разных ОС. Описание утилиты можно прочитать по ссылкам: Windows, Linux. Данная реализация поддерживает Windows, Linux. Macos вероятно, тоже будет работать, но проверить это не удалось ввиду отсутствия данной ОС в пределах досягаемости.
Реализация: файл ping.d
#!/usr/bin/env dub /+ dub.sdl: +/ static int pingTime(string host, int number = 4, int timeout = 400) { import std.process; import std.regex; import std.conv; import std.stdio; import std.range; import std.algorithm; //todo: or `/usr/sbin/`, find its with `ls /usr/bin | grep ping` auto command = ["/usr/bin/ping", "-c", to!string(number), "-q", host, "-W", to!string(timeout)]; auto re = regex(`.*rtt.*=.*\/(?P<time>\d+).\d+\/.*`, "gm"); auto output = pipe(); version (Windows) { import std.path; command = [ buildPath(environment.get("SystemRoot", "C:\\Windows"), "System32", "ping"), "-w", to!string(timeout), "-n", to!string(number), host ]; re = regex(`.*[A|a]verage\s=\s(?P<time>\d+)ms`, "gm"); } auto ping = spawnProcess(command, stdin, output.writeEnd, stderr); auto os = appender!string; output.readEnd.byChunk(4096).copy(os); if (wait(ping) == 0) { auto res = matchFirst(os[], re); if (res["time"] != null) { return to!int(res["time"]); } } return -1; } void main(string[] args) { import std.stdio; pingTime("google.com").writeln; pingTime("ya.ru").writeln; }
Запуск: dub run --single ping.d
В этом коде функция pingTime
принимает IP-адрес или домен сервера, число попыток пинга, таймаут запроса в мс. и возвращает среднее время ответа в мс, если ответ не получен, возвращает -1.
Внутри тела функции происходит запуск процесса утилиты ping с заданными параметрами, ожидание и получение результатов запроса, получение из них среднего времени ответа сервера с помощью регулярного выражения.
Обратите внимание, что утилита ping может иметь разное расположение в системах Posix: /usr/bin/ping
, /usr/sbin/ping
. По этой причине, правильным решением может быть поиск расположения ping с использованием, к примеру, утилиты grep (что в данном коде не реализовано). Также, в большинстве случаев, утилиту можно вызвать просто командой ping
без указания полного пути, но в таком случае, если бинарный файл вашего приложения также называется ping (ping.exe), то ваше приложение будет рекурсивно запускать само себя вместо нужной утилиты, учитывайте это.
Кроме того, для работы утилиты ping в системах Posix требуются права системного администратора, поэтому не забывайте использовать sudo.
Данный способ не универсален, не рекомендуем его использование в критически важных сервисах. Правильным решением будет написание своей реализации ping, с использованием отправки сообщений эхо-запросов протокола ICMP, что позволит избавиться от использования сторонней утилиты.