Java имя удаленного компьютера

3. RMI — Удаленный вызов методов на Java

Java RMI (Remote Method Invocationудаленный вызов методов) представляет собой тип удаленного вызова процедур, независимый от сети, облегченный и полностью переносимый, так как написан на языке Java. Технология RMI основана на более ранней подобной технологии RPC (Remote Procedure Callудаленного вызова процедур) для процедурного программирования, разработанной в 80-х годах. RPC позволяет процедуре вызывать функцию на другом компьютере столь же легко, как если бы эта функция была частью программы, выполняющейся на том же компьютере. Для устранения недостатков RPC была разработана технология RMI, которая обслуживает маршалинг данных через сеть и дает возможность программам на Java передавать законченные объекты Java с помощью механизма сериализации объектов Java. Сериализация — это процесс сохранения состояния объекта в последовательность байт; десериализация это процесс восстановления объекта, из этих байт. Java Serialization API предоставляет стандартный механизм для создания сериализуемых объектов. Маршалинг — по смыслу похож на сериализацию, процесс преобразования представления объекта в памяти в формат данных, пригодный для хранения или передачи. Применительно же к компьютерным сетям, маршалинг означает процесс упаковки данных и преобразования их в стандартный вид перед передачей по сети так, чтобы данные могли пройти через сетевые ограничители. Чтобы передать объект во внешнюю сеть, он должен быть преобразован в поток данных, соответствующий структуре пакетов сетевого протокола. Части данных содержатся в буфере до того момента, пока не будут упакованы. Когда данные переданы, компьютер-получатель преобразует упакованные данные обратно в объект.

1 Основные шаги работы с RMI

  1. Определить удаленный интерфейс, согласованный с сервером.
  2. Написать код сервера.
  3. Запустить программу rmic (Java RMI stub compilerкомпилятор заглушек RMI) для генерации связующего кода.
  4. Написать код клиента.
  5. Убедиться, что на сервере запущен RMI реестр (программа rmiregistry).
  6. Запустить сервер.
  7. Запустить одного или нескольких клиентов.

2 Удалённый интерфейс

Процедуры RMI определяют с помощью известного механизма Java – интерфейсов.

Интерфейс имеет следующий общий синтаксис [5]:

// Заголовок интерфейса interface // Тело интерфейса

Примечание: Интерфейс не предоставляет никакой реализации, поэтому является абстрактным по определению. Это означает, что нельзя создать его экземпляр, но классы могут его реализовывать, предоставляя реализацию для его прототипов методов.

Удаленные интерфейсы должны быть подклассами java.rmi.Remote , при этом и клиент и сервер должны находиться в одном пакете Java. Все параметры удаленных методов должны относиться или к примитивным типам ( int, double и т.п.), либо реализовывать интерфейс java.io.Serializable. Каждый метод удаленного интерфейса должен декларировать java.rmi.RemoteException в своем разделе throws в дополнение ко всем остальным специфичным для приложения исключениям.

Читайте также:  Css указатель мыши при наведении

Пример удалённого интерфейса, который предоставляет службу точного времени:

// интерфейс системы точного времени import java.rmi.*; public interface PerfectTimeI extends Remote

3 Реализация удалённого интерфейса (серверная часть)

Сервер должен содержать класс, который наследуется от UnicastRemoteObject (extends UnicastRemoteObject) и реализует удаленный интерфейс (implements имя интерфейса). Этот класс может также иметь дополнительные методы, но для клиента будут доступны только методы удаленного интерфейса, так как клиент будет получать только ссылку на интерфейс, а не на класс, реализующий его.

Пример реализации удаленного интерфейса PerfectTimeI:

import java.rmi.*; import java.rmi.server.*; import java.rmi.registry.*; import java.net.*; public class PerfectTime extends UnicastRemoteObject implements PerfectTimeI < // Реализация интерфейса: public long getPerfectTime() throws RemoteException < return System.currentTimeMillis(); >// Конструктор, выбрасывающий RemoteException public PerfectTime() throws RemoteException < super(); // вызывается автоматически >// Запуск удалённого объекта, который // выбрасывает исключения на консоль public static void main(String[] args) throws Exception < System.out.println("Initializing PerfectTime…"); // Менеджер безопасности, который поддерживает RMI: System.setSecurityManager(new RMISecurityManager()); // Создание удалённого объекта PerfectTime pt = new PerfectTime(); // Регистрация удалённого объекта PerfectTime в реестре rmiregistry Naming.bind("rmi://localhost:2000/PerfectTime", pt); System.out.println("Ready to do time"); >>

Класс UnicastRemoteObject (пакет java.rmi.server ) предоставляет удалённым объектам базовые функциональные возможности для обслуживания удалённых запросов. Конструкторы и методы класса UnicastRemoteObject возбуждают контролируемое исключение RemoteException, поэтому его подклассы должны определять конструкторы, также возбуждающие исключение RemoteException. По этой причине в подклассе необходимо явно определить конструктор для удаленного объекта, даже если определён только конструктор по умолчанию, который вызывает конструктор базового класса.

Конструктор класса UnicastRemoteObject экспортирует объект, чтобы сделать его доступным для приёма удалённых вызовов. Экспорт объекта даёт возможность удалённому объекту ожидать соединений с клиентами через анонимный порт. Это даёт возможность объекту осуществлять однонаправленное взаимодействие (посредством вызова методов) с использованием сокетов.

4 Настройка реестра

Реестр RMI обслуживается утилитой rmiregistry, и должен быть запущен как отдельный процесс на компьютере. Однако, если наше приложение является единственным, использующим реестр, его можно запускать в самой программе:

Для экспорта удалённого объекта необходимо определить URL , который клиент сможет использовать для получения удалённой ссылки на объект. URL обычно имеет следующий вид:

«rmi://хост:порт/имя удалённого объекта»

где хост – имя компьютера, который выполняет сервер реестра и на нём же выполняется удалённый объект, порт реестра RMI по умолчанию 1099, имя удалённого объекта будет использовать клиент для поиска удалённого объекта в реестре.

Читайте также:  Простейшая регистрация авторизация php

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

Для связывания удалённого объекта с реестром используются статические методы Naming.bind() или Naming.rebind() класса Naming(пакета java.rmi ). Разница между этими методами заключается в том, что если имя удалённого объекта уже есть в реестре, то bind() вызовет исключение AlreadyBoundException, а rebind() заменит существующую запись.

5 Заглушки и скелеты

Для обеспечения правильной работы RMI приложения необходимо создать заглушки и скелеты (вместо скелета используются также термины скелетон или каркас), обеспечивающие сетевое соединение. Для этого служит утилита rmic, входящая в состав Java 2 SE. После её запуска в папке с проектом должны быть созданы два класса _Stub.class и _Skel.class. В нашем примере это будут:

PerfectTime_Stub.class PerfectTime_Skel.class

6 Использование удалённого объекта (клиентская часть)

Клиент, как уже упоминалось выше, взаимодействует с публичным интерфейсом, а не с его реализацией, скрытой от конечного пользователя. Приведённый ниже пример демонстрирует вызов метода getPerfectTime() удалённого объекта PerfectTime, для получения системного времени последнего через интерфейс PerfectTimeI.

// Использование удаленного объекта PerfectTime import java.rmi.*; import java.rmi.registry.*; public class DisplayPerfectTime < public static void main(String[] args) throws Exception < System.setSecurityManager(new RMISecurityManager()); PerfectTimeI t = (PerfectTimeI) Naming.lookup("PerfectTime"); for (int i = 0; i < 10; i++) System.out.println("Perfect time = " + t.getPerfectTime()); >>

Для поиска в реестре удалённого объекта PerfectTime используется статический метод Naming.lookup() (пакета java.rmi ).

7 Запуск приложения

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

Источник

Как получить имя пользователя удаленного пользователя в Java

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

Я старался request.getRemoteUser получил null , пытался System.getenv(«USERNAME») получение авторизованного пользователя на локальном хосте, где находится сервер. Пытался getHostName , System.getProperty получил имя локального хоста. Пробовал это тоже — new com.sun.security.auth.module.NTSystem().getName() но результат тот же.

Я использую java6, windows server и glassfish3 server.

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

4 ответа

Вы хотите сделать что-то под названием SSO (Single Sign On): пользователь где-то вошел в систему (в вашем случае это компьютер с Windows), и вы хотите аутентифицировать пользователя с помощью этого (уже выполненного) входа в систему. Это очень распространенный вариант использования, и для этого есть разные способы. Тем не менее, большой вопрос всегда заключается в том, как вы можете доверять этим сторонним системам. И вот тут начинается беда.

Читайте также:  Thread based application in java

Поскольку ваш вопрос не очень ясен, я предполагаю, что у вас есть сервер Java Glassfish, работающий на Windows Server, и клиент Java (потому что вы запросили код Java). Таким образом, сервер Java должен аутентифицировать, кто является пользователем клиента Java. И сервер должен доверять этой информации.

С помощью System.getProperty(«user.name»); не очень хорошая идея, так как каждый может ее изменить. Вы можете запустить свою программу Java с java -Duser.name=Joe и это все.

Но поскольку вы работаете в Windows, вы можете использовать Windows, чтобы помочь вам. Если оба, ваш клиент и сервер, находятся в одном домене, они аутентифицируются в одной и той же системе. Вы можете попросить эту систему для идентификации пользователя. Обычно машины компании находятся в одном домене.

Для этого есть инструмент под названием Waffle. Он выполняет безопасную проверку подлинности Windows между компьютерами в одном домене. Если ваш клиент и сервер находятся в одном домене, это простой способ выполнить единый вход (единый вход). Вы можете найти его на GitHub: http://dblock.github.io/waffle/

Вот простой пример из одного из моих собственных вопросов пару месяцев назад (см. Здесь):

// client credentials handle IWindowsCredentialsHandle credentials= WindowsCredentialsHandleImpl.getCurrent("Negotiate"); credentials.initialize(); // initial client security context WindowsSecurityContextImpl clientContext = new WindowsSecurityContextImpl(); clientContext.setPrincipalName(Advapi32Util.getUserName()); clientContext.setCredentialsHandle(credentials.getHandle()); clientContext.setSecurityPackage(securityPackage); clientContext.initialize(); // accept on the server WindowsAuthProviderImpl provider = new WindowsAuthProviderImpl(); IWindowsSecurityContext serverContext = null; do < if (serverContext != null) < // initialize on the client SecBufferDesc continueToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, serverContext.getToken()); clientContext.initialize(clientContext.getHandle(), continueToken); >// accept the token on the server serverContext = provider.acceptSecurityToken(clientContext.getToken(), "Negotiate"); > while (clientContext.getContinue() || serverContext.getContinue()); System.out.println(serverContext.getIdentity().getFqn()); for (IWindowsAccount group : serverContext.getIdentity().getGroups()) System.out.println(" " + group.getFqn()); 

Вы можете использовать вафли также для веб-сайтов. Однако я этого не сделал и не могу объяснить, что делать в этом случае.

И одно важное замечание: я думаю, что вы немного смущены. Если вы делаете request.getRemoteHost() на вашем сервере вы пытаетесь получить идентификацию клиента, отправляющего запрос (кстати, это небезопасно, клиент может отправить что угодно). Тем не менее, если вы делаете System.getProperty(«user.name») на вашем сервере вы пытаетесь получить имя самого сервера. Знайте, где вы находитесь (на клиенте или сервере) и что вы хотите. И убедитесь, можете ли вы доверять этой информации или нет. Безопасность это сложно.

Источник

Оцените статью