Читайте также: |
|
Для обработки сетевых данных в Java применяется технология вызова удаленных методов (RMI – Remote Method Invocation), реализованная в пакетах java.rmi и java.rmi.server. Эта технология позволяет разрабатывать мощные сетевые приложения, облегчая задачи программиста по организации доступа к сетевым данным. Она расширяет возможности технологии «клиент-сервер» за счет определения сервером объектов для использования сетевыми клиентами. Клиенты получают возможность работать с сетевыми данными таким же образом, если б они были локальными, внутри той же виртуальной машины, что и клиент. RMI скрывает от пользователя рутинные операции по организации обмена данными, транспортировки параметров методов и возвращаемых значений через сеть. Для создания приложений с использованием RMI необходимо произвести следующие действия:
· создать интерфейс на базе java.rmi.Remote, в котором определены экспортируемые методы, реализуемые на уровне сервера. Каждый метод этого интерфейса при этом должен обладать возможностью генерации исключений java.rmi.RemoteException для предотвращения сетевых коллизий;
· определить класс, производный от java.rmi.server, реализующий сетевой интерфейс. Например, UnicastRemoteObject, который представляет серверный объект с автоматической обработкой данных;
· создать программу, реализующую экземпляр сетевого объекта на сервере и организовать доступ к ней на основе регистрации имени объекта в службе реестра с помощью класса java.rmi.Naming. Такая серверная программа может сама выполнять функции сервера реестра, используя класс LocateRegistry;
· после компиляции серверной программы с помощью команды javac, запустить утилиту rmic для генерации к сетевому объекту заглушки (stub) и каркаса (skeleton). Технология RMI не предусматривает организации взаимодействия клиента с сервером, так как на стороне клиента ссылка на объект сетевых данных реализуется в виде экземпляра класса заглушки. Заглушка производит сетевые операции по передаче вызова классу каркасу на сервере, который и передает возвращаемые методом значения заглушке, а затем клиенту. При запуске утилиты rmic с указанием имени сетевого класса объекта автоматически будут созданы два новых класса с суффиксами _Stub и _Skel;
· запустить сервер реестра вызовом программы rmiregistry;
· теперь создать клиентскую программу, использующую экспортированный сервером сетевой объект с полученной на него ссылкой в форме rmi:URL. Далее методы сетевого объекта можно вызывать так же как и локального.
Пример 8.1. Сетевое банковское обслуживание на основе класса Bank, содержащего внутренние классы и интерфейсы клиент-серверной банковской системы:
· RemoteBank – сетевой интерфейс, реализуемый сервером и используемый клиентом банка;
· FunnyMoney – простейший класс для представления денег банковского обслуживания;
· BankingException – подкласс исключений для предотвращения различных коллизий, например, «недостаток денежных средств»;
· Client – класс, являющийся автономной программой, выполняющей функции клиента банковского сервера. Он использует метод Naming.Lookup() для поиска в системном реестре нужного объекта RemoteBank с последующим вызовом различных методов этого объекта.
package Bank.java;import java.rmi.*;import java.util.List; /** * Этот класс является контейнером, содержащим другие классы * и интерфейсы банковской системы. **/public class Bank { /** * Интерфейс, определяющий методы, экспортируемые * банковским сервером. **/ public interface RemoteBank extends Remote { /** открытие счета с указанием имени и пароля */ public void openAccount(String name, String password) throws RemoteException, BankingException; /** закрытие счета */ public FunnyMoney closeAccount(String name, String password) throws RemoteException, BankingException; /** снятие денег со счета */ public void deposit(String name, String password, FunnyMoney money) throws RemoteException, BankingException; /** снятие денежной суммы со счета */ public FunnyMoney withdraw(String name, String password, int amount) throws RemoteException, BankingException; /** возвращение суммы, хранящейся на счете */ public int getBalance(String name, String password) throws RemoteException, BankingException; /** * возвращение списка строк с проводками счета **/ public List getTransactionHistory(String name, String password) throws RemoteException, BankingException; } /** * класс денежного счета. **/ public static class FunnyMoney implements java.io.Serializable { public int amount; public FunnyMoney(int amount) { this.amount = amount; } } /** * тип исключений для предотвращения различных коллизий **/ public static class BankingException extends Exception { public BankingException(String msg) { super(msg); } } /** * клиентская программа, взаимодействующая с сервером * RemoteBank при помощи RMI. **/ public static class Client { public static void main(String[] args) { try { // определение места RemoteBank для соединения String url = System.getProperty("bank", "rmi:///FirstRemote"); // поиск сервера RemoteBank с использованием объекта Naming // по заданному url вызов возвращает объект // RemoteBank, методы которого используются в сети RemoteBank bank = (RemoteBank) Naming.lookup(url); // преобразование команды пользователя String cmd = args[0].toLowerCase(); // проверка команды на совпадение if (cmd.equals("open")) { // открыть счет bank.openAccount(args[1], args[2]); System.out.println("Account opened."); } else if (cmd.equals("close")) { // закрыть счет FunnyMoney money = bank.closeAccount(args[1], args[2]); // валюта System.out.println(money.amount + " вам возвращено."); System.out.println("большое спасибо"); } else if (cmd.equals("deposit")) { // внесение денег FunnyMoney money=new FunnyMoney(Integer.parseInt(args[3])); bank.deposit(args[1], args[2], money); System.out.println("пополнено " + money.amount + " денег"); } else if (cmd.equals("withdraw")) { // снятие денег FunnyMoney money = bank.withdraw(args[1], args[2], Integer.parseInt(args[3])); System.out.println("снято " + money.amount + " денег"); } else if (cmd.equals("balance")) { // баланс счета int amt = bank.getBalance(args[1], args[2]); System.out.println("на счету " + amt + " денег"); } else if (cmd.equals("history")) { // выписка проводок List transactions = bank.getTransactionHistory(args[1], args[2]); for(int i = 0; i < transactions.size(); i++) System.out.println(transactions.get(i)); } else System.out.println("неизвестная команда"); } // перехват и вывод исключений RMI catch (RemoteException e) { System.err.println(e); } // исключения по объекту Banking catch (BankingException e) { System.err.println(e.getMessage()); } // другие ошибки catch (Exception e) { System.err.println(e); System.err.println("Usage: java [-Dbank=<url>] Bank$Client " + "<cmd> <name> <password> [<amount>]"); System.err.println("where cmd is: open, close, deposit, " + "withdraw, balance, history"); } } }}
Пример 8.2. Реализация класса RemoteBankServer – серверной части для для предыдущей клиентской программы.
package RemoteBankServer.java;import java.rmi.*;import java.rmi.server.*;import java.util.*;import Bank.*; /** * класс реализует методы, определенные интерфейсом RemoteBank**/public class RemoteBankServer extends UnicastRemoteObject implements RemoteBank{ /** * вложенный класс хранит данные об отдельном счете **/ class Account { String password; // пароль счета int balance; // баланс счета List transactions = new ArrayList(); // история проводок Account(String password) { this.password = password; transactions.add("Account opened at " + new Date()); } } /** * матрица для хранения всех открытых счетов и связи имени счета * с объектом Account **/ Map accounts = new HashMap(); /** * конструктор исключения **/ public RemoteBankServer() throws RemoteException { super(); } /** * открытие счета с именем и паролем **/ public synchronized void openAccount(String name, String password) throws RemoteException, BankingException { // проверка имени счета if (accounts.get(name)!= null) throw new BankingException("счет уже существует"); // если не существует, то создать Account acct = new Account(password); // и зарегистрировать accounts.put(name, acct); } /** * проверка имени и пароля счета **/ Account verify(String name, String password) throws BankingException { synchronized(accounts) { Account acct = (Account)accounts.get(name); if (acct == null) throw new BankingException("нет такого счета"); if (!password.equals(acct.password)) throw new BankingException("неверный пароль"); return acct; } } /** * закрытие счета. **/ public synchronized FunnyMoney closeAccount(String name, String password) throws RemoteException, BankingException { Account acct; acct = verify(name, password); accounts.remove(name); // перед изменением баланса блокирум счет synchronized (acct) { int balance = acct.balance; acct.balance = 0; return new FunnyMoney(balance); } } /** пополнение счета FunnyMoney */ public void deposit(String name, String password, FunnyMoney money) throws RemoteException, BankingException { Account acct = verify(name, password); synchronized(acct) { acct.balance += money.amount; acct.transactions.add("внесено " + money.amount + " в " + new Date()); } } /** снятие суммы с указанного счета */ public FunnyMoney withdraw(String name, String password, int amount) throws RemoteException, BankingException { Account acct = verify(name, password); synchronized(acct) { if (acct.balance < amount) throw new BankingException("нет средств"); acct.balance -= amount; acct.transactions.add("снято " + amount + " с "+new Date()); return new FunnyMoney(amount); } } /** текущий баланс счета */ public int getBalance(String name, String password) throws RemoteException, BankingException { Account acct = verify(name, password); synchronized(acct) { return acct.balance; } } /** * строки с историей проводок по счету **/ public List getTransactionHistory(String name, String password) throws RemoteException, BankingException { Account acct = verify(name, password); synchronized(acct) { return acct.transactions; } } /** * основная программа, выполняющая RemoteBankServer. * создание объекта RemoteBankServer с присвоением имени в реестре * определяем имя по умолчанию "FirstRemote" **/ public static void main(String[] args) { try { // создание объекта банковского сервера RemoteBankServer bank = new RemoteBankServer(); // его имя String name = System.getProperty("bankname", "FirstRemote"); // присвоение имени Naming.rebind(name, bank); // готовность к работе System.out.println(name + " открыт для работы с клиентами"); } catch (Exception e) { System.err.println(e); System.err.println("формат: java [-Dbankname=<name>] " + " RemoteBankServer.java "); System.exit(1); // принудительный выход } }}
Дата добавления: 2015-09-11; просмотров: 71 | Поможем написать вашу работу | Нарушение авторских прав |