Java: встраиваем сервер Telnet::Журнал СА 5.2004
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Дата-центры  

Дата-центры: есть ли опасность утечки данных?

Российские компании уже несколько лет испытывают дефицит вычислительных мощностей. Рост числа проектов,

 Читать далее...

Книжная полка  

Защиты много не бывает

Среди книжных новинок издательства «БХВ» есть несколько изданий, посвященных методам социальной инженерии

 Читать далее...

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

Обычно соответствие программного продукта требованиям мы проверяем через скоуп вполне себе понятных

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6311
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 7020
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4302
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 3056
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3852
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3868
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6359
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3211
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3502
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7322
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10685
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12409
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 14050
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9172
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7119
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5428
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4660
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3465
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3191
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3434
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3063
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 Java: встраиваем сервер Telnet

Архив номеров / 2004 / Выпуск №5 (18) / Java: встраиваем сервер Telnet

Рубрика: Программирование /  Анализ данных   | Дополнительные материалы

АЛЕКСАНДР ФЕФЕЛОВ

Java: встраиваем сервер Telnet

В процессе работы над одним Java-проектом я столкнулся с необходимостью удаленного управления серверным приложением. Разрабатывать полновесный графический интерфейс пользователя (GUI) мне показалось нерациональным. Ведь если GUI создать на базе Swing или SWT, то придется устанавливать дополнительные программы (JRE и собственно GUI) на клиентских рабочих местах. А если GUI построить на основе JSP, то дополнительные программы (JSP-контейнер) придется устанавливать на сервере. В то же время проект был рассчитан на эксплуатацию квалифицированным персоналом, которому нет нужды до свистулек и погремушек графического интерфейса. Значит, вполне подходящим выбором могли быть доступные удаленно интерфейс командной строки (CLI) или текстовый интерфейс пользователя (TUI). Наиболее очевидный выбор для реализации удаленных CLI и TUI – это Telnet (RFC 854). Данная статья и посвящена встраиванию функционала сервера Telnet в Java-приложения.

TelnetD

Инструмент, способный помочь в решении поставленной задачи, был быстро найден. Это TelnetD – встраиваемый многопоточный сервер Telnet, реализованный на языке Java Дитером Вимбергером (Dieter Wimberger). TelnetD поставляется в виде исходных текстов по модифицированной лицензии BSD. На момент написания статьи была доступна версия 1.0.

Архитектура TelnetD

Центральным объектом TelnetD является сервер (Daemon по терминологии разработчика), который создает все другие необходимые для работы объекты – слушателей (Listeners), менеджер оболочек (ShellManager) и менеджер терминалов (TerminalManager).

Слушатели принимают и управляют сетевыми соединениями от клиентских программ.

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

Поддержка конкретных реализаций терминалов (таких как ANSI, VT100 или xterm), возложена на менеджер терминалов.

Все перечисленные компоненты TelnetD конфигурируются с помощью объектов java.util.Properties, а значит настройки можно хранить в обычных текстовых файлах.

Для встраивания TelnetD в программу нужно всего лишь запрограммировать собственный интерпретатор командной строки, реализующий необходимую логику взаимодействия с пользователем.

Начнем…

Для работы с TelnetD нам понадобятся:

  • дистрибутив TelnetD, включающий исходные тексты (файл telnetd-1.0.zip) и документацию (файл telnetd-1.0_docs.zip);
  • инструментарий Apache Ant. (В задачи данной статьи не входит описание работы с Ant. Будем предполагать, что Ant уже установлен и настроен.)

Развернем дистрибутив и скомпилируем TelnetD, выполнив в каталоге установки команду:

ant jar

При компиляции будут выданы предупреждения об использовании устаревшего (deprecated) метода java.lang. Thread.stop(), которые могут быть безболезненно проигнорированы. В результате компиляции в каталоге build будет создан файл telnetd.jar. (Обратите внимание на его малый размер. В моем случае – всего 86060 байт.)

Теперь скопируем все файлы из каталога src et wimpi elnetd esources в каталог build, в нем выполним команду:

java -classpath telnetd.jar net.wimpi.telnetd.TelnetD

которая запустит сервер TelnetD на выполнение в демонстрационном режиме, и попытаемся установить соединение с сервером с помощью команды:

telnet localhost 6666

Voila! Наш сервер работает.

Пример использования TelnetD

Как было сказано выше, для встраивания TelnetD в программу необходимо создать свой класс для интерпретатора командной строки. Этот класс должен реализовывать интерфейс Shell из пакета net.wimpi.telnetd.shell.

Следует отметить, что интерфейс Shell является расширением интерфейса ConnectionListener из пакета net. wimpi.telnetd.net. А это значит, что интерпретатор командной строки должен предоставлять методы, реагирующие на события соединения.

Мы создадим максимально простой интерпретатор, который будет ждать ввода пользователем какого-либо символа и выполнять соответствующее действие. Набор действий невелик – это выдача дополнительной информации о сеансе, завершение сеанса и останов сервера. Итак, код:

package telnetdtest;

import net.wimpi.telnetd.*;

import net.wimpi.telnetd.io.*;

import net.wimpi.telnetd.net.*;

import net.wimpi.telnetd.shell.*;

public class Test1Shell implements Shell {

  // Создание экземпляра интерпретатора командной строки (оболочки). Этот метод, хотя и не описан в интерфейсе Shell, должен быть

  // реализован, так как он используется менеджером оболочек для создания экземпляра конкретной оболочки

  public static Shell createShell() {

    return new Test1Shell();

  }

  // Собственно интерпретатор

  public void run(Connection con) {

    connection = con;

    termIO = (TerminalIO) connection.getTerminalIO();

    // Регистрируем этот объект в качестве обработчика событий соединения

    this.connection.addConnectionListener(this);

    // Выводим баннер, содержащий номер версии TelnetD

    termIO.write("TelnetD testbed 1"

      + CRLF + "TelnetD version: "

      + TelnetD.getReference().getVersion() + CRLF);

    termIO.flush();

    while (true) {

      // Выводим подсказку

      termIO.write(CRLF

        + "Press [i] for information," + CRLF

        + "[x] for exit," + CRLF + "[s] for shutdown"

        + CRLF + CRLF);

      termIO.flush();

      // Ждем ввода от пользователя

      int ch = termIO.read();

      // Реагируем соответствующим образом

      switch (ch) {

        case 120: // x - завершение сеанса

          termIO.write("Goobye!");

          termIO.flush();

          connection.close();

          return;

        case 115: // s - останов сервера

          termIO.write("Requiescat in pace!");

          termIO.flush();

          TelnetD.getReference().setServing(false);

          TelnetD.getReference().shutdown();

          System.exit(0);

          return;

        case 105: // i - информация о сервере и сеансе

          // Получаем данные о соединении

          ConnectionData data =

            connection.getConnectionData();

          // Выводим данные на экран

          termIO.write("Additional info:" + CRLF);

          termIO.write("Connected from: "

            + data.getHostName()

            + " [" + data.getHostAddress() + ":"

            + data.getPort() + "]" + CRLF);

          termIO.write("Guessed locale: "

            + data.getLocale() + CRLF);

          termIO.write("Negotiated terminal type: "

            + data.getNegotiatedTerminalType() + CRLF);

          termIO.write("Scrolling support: "

            + (termIO.getTerminal().supportsScrolling() ?

              "yes" : "no") + CRLF);

          termIO.write("Graphics rendition support: "

            + (termIO.getTerminal().supportsSGR() ?

              "yes" : "no") + CRLF);

          termIO.write("Negotiated columns: "

            + data.getTerminalColumns() + CRLF);

          termIO.write("Negotiated rows: "

            + data.getTerminalRows() + CRLF);

          termIO.write("Login shell: "

            + data.getLoginShell() + CRLF);

          termIO.flush();

          break;

      }

    }

  }

  // Реакция на событие соединения: таймаут

  public void connectionTimedOut(ConnectionEvent ce) {

    termIO.write("*** Connection timedout" + CRLF);

    termIO.flush();

    connection.close();

  }

  // Реакция на событие соединения: бездействие

  public void connectionIdle(ConnectionEvent ce) {

    termIO.write("*** Connection idle" + CRLF);

    termIO.flush();

  }

  // Реакция на событие соединения: запрос на разрыв соединения (Ctrl+D)

  public void connectionLogoutRequest(ConnectionEvent ce) {

    termIO.write("*** Connection logout request" + CRLF);

    termIO.flush();

  }

  // Реакция на событие соединения: разрыв соединения

  public void connectionBroken(ConnectionEvent ce) {

    termIO.write("*** Connection broken" + CRLF);

    termIO.flush();

  }

  // Реакция на событие соединения: сигнал NVT BREAK

  public void connectionSentBreak(ConnectionEvent ce) {

    termIO.write("*** Connection break" + CRLF);

    termIO.flush();

  }

  private Connection connection;

  private TerminalIO termIO;

  private final String CRLF = BasicTerminalIO.CRLF;

}

Конфигурационный файл для нашего примера описывает параметры ведения протоколов работы TelnetD, перечни известных терминалов, оболочек и слушателей с указанием реализующих их классов и параметров:

#=====================================================

# Параметры системных журналов

#=====================================================

syslog=on

syslog.media=terminal

syslog.stampformat=[yyyy-MM-dd hh:mm:ss z]

syslog.path=

#=====================================================

# Параметры отладочных журналов

#=====================================================

debuglog=off

debuglog.media=terminal

debuglog.stampformat=[yyyy-MM-dd hh:mm:ss z]

debuglog.path=

#=====================================================

# Терминалы

#=====================================================

# Известные терминалы

terminals=vt100,ansi,windoof,xterm

# Классы терминалов

term.vt100.class=net.wimpi.telnetd.io.terminal.vt100

term.ansi.class=net.wimpi.telnetd.io.terminal.ansi

term.windoof.class=net.wimpi.telnetd.io.terminal.Windoof

term.xterm.class=net.wimpi.telnetd.io.terminal.xterm

# Алиасы терминалов

term.vt100.aliases=default,vt100-am,vt102,dec-vt100

term.ansi.aliases=color-xterm,xterm-color,vt320,vt220,linux

term.windoof.aliases=

term.xterm.aliases=

#=====================================================

# Оболочки

#====================================================

# Известные оболочки

shells=myShell

#-------------------------------------------

# Параметры оболочки myShell

#-------------------------------------------

# Класс оболочки

shell.myShell.class=telnetdtest.Test1Shell

#=====================================================

# Слушатели

#=====================================================

# Известные слушатели

listeners=myListener

#-------------------------------------------

# Параметры слушателя myListener

#-------------------------------------------

# Порт, на котором слушатель ожидает соединения

myListener.port=7241

# Максимальное количество запросов на соединение (защита от флуда)

myListener.floodprotection=5

# Максимальное количество активных соединений

myListener.maxcon=10

# Максимальное количество соединений, ожидающих активизации

myListener.maxqueued=0

# Время бездействия соединения

myListener.time_to_warning=300000

# Время таймаута соединения

myListener.time_to_timedout=100000

# Периодичность проверки бездействия и таймаута

myListener.housekeepinginterval=1000

# Режим ввода

myListener.inputmode=character

# Имя оболочки, запускаемой слушателем

myListener.loginshell=myShell

# Класс фильтра соединений

myListener.connectionfilter=

Теперь создадим программу, которая запустит наш Telnet-сервер:

package telnetdtest;

import java.io.*;

import java.util.*;

import net.wimpi.telnetd.*;

public class Test1 {

  public static void main(String[] args)

    throws Exception {

    System.out.println("TelnetD testbed 1");

    // Загружаем настройки TelnetD из файла

    Properties settings = new Properties();

    settings.load(new FileInputStream("test1.properties"));

    // Создаем сервер

    TelnetD daemon = TelnetD.createTelnetD(settings);

    // Разрешаем серверу работать

    daemon.setServing(true);

  }

}

Интерфейс пользователя

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

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

Активные компоненты представлены однострочным (класс Editfield) и многострочным (класс Editarea) редакторами, меню (класс Selection), флажком (класс Checkbox) и пейджером (класс Pager). Для работы с активным компонентом необходимо создать нужный объект, вызвать соответствующие методы для настройки параметров, вызвать метод run(), приводящий к активизации компонента, и, наконец, вызвать метод getValue() для получения результатов работы компонента.

Пассивные компоненты – это метка (класс Label), строки заголовка (класс Titlebar) и статуса (класс Statusbar). Для пассивного компонента после создания и настройки параметров необходимо вызывать метод draw(), что приведет к отображению компонента.

Посмотрим некоторые из этих компонентов в деле. Для этого изменим код метода run(…) в интерпретаторе из первого примера. Теперь он выглядит так:

  public void run(Connection con) {

    connection = con;

    termIO = (TerminalIO) connection.getTerminalIO();

    // Регистрируем этот объект в качестве обработчика событий соединения

    this.connection.addConnectionListener(this);

    while (true) {

      // Очищаем экран

      termIO.eraseScreen();

      // Создаем и отображаем строки заголовка и статуса

      Titlebar title = new Titlebar(termIO, "");

      title.setTitleText("TelnetD testbed 2");

      title.setForegroundColor(ColorHelper.YELLOW);

      title.setBackgroundColor(ColorHelper.BLUE);

      title.setAlignment(Titlebar.ALIGN_CENTER);

      title.draw();

      Statusbar status = new Statusbar(termIO, "");

      status.setStatusText("TelnetD version: "

        + TelnetD.getReference().getVersion());

      status.setForegroundColor(ColorHelper.YELLOW);

      status.setBackgroundColor(ColorHelper.BLUE);

      status.setAlignment(Statusbar.ALIGN_RIGHT);

      status.draw();

      // Выводим подсказку к меню

      termIO.homeCursor();

      termIO.moveCursor(BasicTerminalIO.DOWN, 5);

      termIO.write(CRLF + "Use arrow keys to select "

        + "command, [Enter] or [Tab] to run command"

        + CRLF + "Command:" + CRLF);

      termIO.flush();

      // Создаем меню выбора и активизируем его

      Selection menu = new Selection(termIO, "");

      menu.addOption("Editfield demo");

      menu.addOption("Editarea demo");

      menu.addOption("Exit");

      menu.addOption("Shutdown");

      menu.run();

      // Получаем выбор пользователя

      int cmd = menu.getSelected();

      // Реагируем соответствующим образом

      switch (cmd) {

        case 0: // демонстрация возможностей однострочного редактора

          termIO.eraseScreen();

          termIO.homeCursor();

          termIO.write("Editfield demo" + CRLF

            + "--------------" + CRLF);

          final int MAX_EDITFIELD_CHARS = 20;

          // Выводим подсказку к редактору

          termIO.write(CRLF + "Type any text (max "

            + MAX_EDITFIELD_CHARS + " chars), press "

            + "[Enter] or [Tab] to finish typing"

            + CRLF + "Text:" + CRLF);

          termIO.flush();

          // Создаем однострочный редактор

          Editfield editfield = new Editfield(termIO,

            "", MAX_EDITFIELD_CHARS);

          // Ждем ввода от пользователя

          editfield.run();

          // Показываем пользователю результат

          termIO.write(CRLF + "Your input: " + CRLF

            + editfield.getValue() + CRLF);

          termIO.flush();

          break;

        case 1: // демонстрация возможностей многострочного редактора

          termIO.eraseScreen();

          termIO.homeCursor();

          termIO.write("Editarea demo" + CRLF

            + "-------------" + CRLF);

          final int MAX_EDITAREA_ROWS = 4;

          // Выводим подсказку к редактору

          termIO.write(CRLF + "Type any text (max "

            + MAX_EDITAREA_ROWS + " rows), press [Tab] "

            + "to finish typing" + CRLF + "Text:" + CRLF);

          termIO.flush();

          // Создаем многострочный редактор

          Editarea editarea = new Editarea(termIO, "",

            MAX_EDITAREA_ROWS, MAX_EDITAREA_ROWS);

          // Ждем ввода от пользователя

          editarea.run();

          // Показываем пользователю результат

          termIO.write(CRLF + "Your input: " + CRLF

            + editarea.getValue() + CRLF);

          termIO.flush();    

          break;

        case 2: // завершение сеанса

          connection.close();

          return;

        case 3: // останов сервера

          TelnetD.getReference().setServing(false);

          TelnetD.getReference().shutdown();

          System.exit(0);

          return;

      }

      // Ждем, пока пользователь нажмет любую клавишу

      termIO.write(CRLF + "Press any key");

      termIO.flush();

      termIO.read();

    }

  }

Заключение

Итак, используя TelnetD, можно с минимальными затратами обеспечить возможность удаленного управления Java-приложением по протоколу Telnet.

Здесь, однако, следует отметить, что протокол Telnet передает все данные «открытым текстом», а значит, использование его в публичных сетях небезопасно. В качестве альтернативы протоколу Telnet для применения в публичных сетях можно предложить нестандартные расширения протокола Telnet или протокол SSH.

Ссылки:

  1. http://www.faqs.org/rfcs/rfc854.html – спецификация протокола Telnet.
  2. http://telnetd.sourceforge.net – домашняя страница TelnetD.
  3. http://ant.apache.org – домашняя страница Jakarta Ant.
  4. http://www.pvv.ntnu.no/~asgaut/crypto/thesis/thesis.html – вариант модификации протокола Telnet с целью повышения безопасности.
  5. http://www.ietf.org/html.charters/secsh-charter.html – материалы рабочей группы IETF Secure Shell по стандартизации протокола SSH.

Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru