Продолжаю тему, начатую в предыдущей заметке [КОПИЯ]. В ней описывал получение данных от определенных скриптов и процессов запущенных на сервере под управлением Linux с помощью SSH, псевдотерминала и отдельного пользователя, создаваемого специально для целей мониторинга.
Будем посмотреть другой способ, с одной стороны, более сложный и требующий владения каким-нибудь языком программирования, кроме Bash-скриптов. Хотя, можно обойтись и исключительно одним Bash’ем, если клиент и сервер под Linux, или Bash прикрутили к Windows (cygwin(?), не пробовал, не знаю). А с другой стороны, наоборот, способ простой безопасный, требующий минимум вмешательства в настройки сервера.
На полноценный мануал не рассчитывайте, так, заметки на полях рабочего блокнота, чтоб не забыть и потом допилить под свои личные нужды.
Примечание: Термины «клиент» и «сервер» могут по ходу статьи быть неоднозначно истолкованными.
Серверное приложение будет наоборот, работать на «клиентском», «операторском» рабочем месте, а «сервер», в смысле компьютер с Linux, на котором я запускаю свои скрипты, и который управляет нужной мне железякой, станет вполне себе клиентом.
В общем, чтобы не вносить путаницы я условлюсь называть рабочее место оператора «локальным компьютером», а тот, который «сервер в привычном понимании» — «удаленным».
Такая же, как и в предыдущей заметке. Имеется удаленный компьютер под управлением Linux, рулящий системой контроля температуры и давления.
На самом деле, рулить он может чем угодно: от домашнего FTP с котиками или соединения с Интернетом, до управления СКД, открытием ворот, дверей, врат в Ад, личным концлагерем и т.д.
Суть в том, что нужно, чтобы удаленная система сигнализировала оператору об изменении своего состояния (изменении температуры, разрыва соединения с Интернетом, пришествии Сатаны). Оператор, как обычно, сидит под Windows (как в большинстве организаций в СНГ).
Для простоты условимся, что локальный и удаленный компьютер находятся в одной локальной сети (и одной подсети) 10.10.0.0/24
, IP-адрес локального компьютера 10.10.0.30
, прием данных производится через сетевой порт 11000
локального компьютера. Локальный и удаленный компьютеры обмениваются данными по протоколу TCP, данные представляют собой Unicode-строки.
Для приема сообщений была создана программа-сервер, написанная на C# слушающая входящие сообщения на порту 11000
локального компьютера и выводящая их на консоль.
Никаких проверок, естественно, нет, использовать можно только для себя и работает оно идеально только в лабораторных условиях. Ссылка на весь код ниже. Кратко остановлюсь лишь на некоторых моментах:
//устанавливаем параметры сокета IPHostEntry ipHost = Dns.GetHostEntry("10.10.0.30"); IPAddress ipAddr = ipHost.AddressList[0]; IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000); //создаем его Socket sListener = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp); ... //слушаем входящие соединения sListener.Bind(ipEndPoint); sListener.Listen(10); while (true) //НИКОГДА не делайте так в реальных программах { Console.WriteLine("Ожидаем соединение через порт {0}", ipEndPoint.Port); Console.WriteLine("Локальный адрес {0}", ipEndPoint.Address); // Программа приостанавливается, ожидая входящее соединение Socket handler = sListener.Accept(); string data = null; // Мы дождались клиента, пытающегося с нами соединиться byte[] bytes = new byte[1024]; Console.WriteLine("Сообщение получено, ожидаем данные (5 с)"); Thread.Sleep(5000); //НИКОГДА так не делайте, чтобы //не потерять входящие данные, используйте асинхронные методы, например //и разработайте свой протокол высокого уровня с маркерами конца сообщения //подтверждениями приема данных и прочими нужными вещами!!! ...
Смотреть весь код
Скачать с Mega.nz
Основано на коде из статьи
Bash, как оказывается, имеет возможность обмениваться сообщениями по локальной сети, а точнее, записывать и считывать нужные данные в порт на компьютер с определенным адресом (как IP, так и поименованном). Для ознакомления со всеми возможностями, настоятельно рекомендую обратиться к разделу источников в конце заметки. Здесь же я опять, остановлюсь только на основных командах.
#!/bin/bash
echo "Open"
exec 3>/dev/tcp/10.10.0.30/11000
Ключевая команда здесь exec
. С ее помощью открываем нужный сокет, тем самым соединяясь с необходимым компьютером на определенном порту.
где:
3
— Файловый дескриптор. Дескрипторы 0
, 1
и 2
зарезервированы, соответственно за устройствами stdin
, stdout
и stderr
. Для своих нужд можно использовать дескрипторы, начиная с 3
, в стандартных случаях они никем не используются, а нестандартные я позволю себе опустить.
tcp
— указание на протокол (точнее, на виртуальное устройство, ассоциируемое с этим протоколом). Обычно принимает значения tcp
или udp
.
>
— указание, что сокет открыт для записи. Возможны варианты <
— для чтения. <>
— для чтения и записи.
10.10.0.30
— IP (или URL) компьютера, которому посылаем (принимаем) сообщения.
11000
— номер порта.
Примечание: Порт должен быть открыт в файерволе на локальном и удаленном компьютере.
Примечание: Для получения возможности открытия сокетов средствами командной оболочки bash необходима активация механизма поддержки виртуальных файлов устройств сокетов на этапе сборки бинарного файла этой командной оболочки из исходных кодов (т.е., его сборки с активацией возможности «—enable-net-redirections»). В устаревших версиях дистрибутивов данная возможность bash может быть деактивирована, причем в этом случае вы будете получать следующее сообщение об ошибке после каждой попытки открытия сокета:
/dev/tcp/xmodulo.com/80: No such file or directory
Помимо командной оболочки bash, виртуальные устройства сокетов поддерживаются такими командными оболочками, как ksh и zsh.[2]
Отправить сообщение в открытый сокет можно с помощью команды echo
:
echo -e $1 >&3
В данном примере, после отправки каждого сообщения, сокет нужно закрывать, освобождая дескриптор файла. Возможно, это можно как-то побороть и держать сокет открытым постоянно, но у меня не сработало.
exec 3>&-
где:
3
— вышеупомянутый дескриптор файла
>
— должно принимать соответствующие значения для открытого на запись (>
), чтение (<
) или двунаправленного сокета (<>
). Двунаправленный сокет должно быть можно превратить в однонаправленный, если это вдруг понадобится.
&-
— указание на закрытие соответствующего сокета.
Сервера приема сообщений:
— Смотреть на PasteBin
— Скачать с Mega.nz
Скрипта отправки сообщений:
— Смотреть на PasteBin
— Скачать с Mega.nz
1. Клиент-серверное приложение на потоковом сокете TCP [Копия]
2. Как открыть TCP-/UDP-сокет средствами командной оболочки bash [Копия]