Очки знаний:
1) Что такое рми
2) Простая реализация rmi
3) принцип РМИ
4) Рукописная структура RMI
Давайте сначала поговорим о RPC?
Протокол удаленного вызова процедур
Не зная специфики, вызов метода класса в удаленной системе аналогичен вызову локального метода.
Протокол RPC на самом деле является спецификацией.
В том числе Dubbo, Thrift, rmi, webservice, hessain
Сетевые протоколы и сетевой ввод-вывод прозрачны для вызывающей стороны и сервера.
Элементы, которые должна содержать структура RPC:
Обзор RMI
rmi (вызов удаленного метода) вызов удаленного метода
Можно рассматривать как Java-версию RPC.
RMI использует JRMP (JAVA Remote Messageing Protocol).Можно сказать, что JRMP — это коммуникационный протокол, специально настроенный для java, поэтому это чисто распределенное решение java.
Как реализовать программу RMI
1) Создайте удаленный интерфейс и наследуйте интерфейс java.rmi.Remote.
package com.llf.rmidemo;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface SayHello extends Remote{
public String sayHello(String name)throws RemoteException;
}
2) Реализовать наш удаленный интерфейс и унаследовать UnicastRemoteObject
package com.llf.rmidemo;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class SayHelloImpl extends UnicastRemoteObject implements SayHello{
protected SayHelloImpl() throws RemoteException {
}
@Override
public String sayHello(String name) throws RemoteException {
return "Hello LLF -->"+name;
}
}
3) Создайте серверную программу и вызовите метод createRegistry для регистрации удаленного объекта.
package com.llf.rmidemo;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class HelloServer {
public static void main(String[] args) {
try {
SayHello hello=new SayHelloImpl();
LocateRegistry.createRegistry(8888);
try {
Naming.bind("rmi://localhost:8888/sayhello", hello);
System.out.println("Server start success!");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (AlreadyBoundException e) {
e.printStackTrace();
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
4) Создать клиентскую программу
package com.llf.rmidemo;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class HelloClient {
public static void main(String[] args) {
try {
SayHello hello=(SayHello) Naming.lookup("rmi://localhost:8888/sayhello");
System.out.println(hello.sayHello("FXP"));
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
}
результат:
Внедрите RMI самостоятельно
1) Напишите серверную программу, выставьте прослушиватели и используйте сокеты. 2) Написать клиентскую программу, подключиться к указанному сервису через IP и порт и инкапсулировать (сериализовать) наши данные 3) Когда сервер получает запрос, он сначала десериализует его для обработки бизнес-логики, а затем сериализует и возвращает возвращаемый результат.
схема последовательности вызовов rmi framework
анализ исходного кода rmi
Мы можем почти понять это с помощью следующей диаграммы: а) Идентификаторы заглушки и скелета существуют как прокси. Клиент называется заглушкой, а сервер называется скелетом. Эти два объекта скрывают специфические детали удаленных вызовов методов. Эти два необходимы. b) Реестр: Реестр, который обеспечивает сопоставление имен сервисов с сервисами.
В сочетании с приведенным выше изображением и демонстрационным кодом выше, давайте взглянем на базовый исходный код rmi. Во-первых, давайте посмотрим на серверную часть, которая предоставляет услугу метод createRegistry Сначала сервер создает объект RegistryImpl, а затем выполняет проверку безопасности, здесь не нужно обращать внимание, основное внимание уделяется методу установки. Войдите в класс RegistryImpl Затем введите метод exportObject UnicastServerRef. 1) Сначала создайте заглушку прокси-объекта для входящего RegistryImpl. 2) Установите объект скелета UnicastServerRef в текущий объект RegistryImpl. 3) скелет, заглушка, объект unicastserverRef, идентификатор и логическая конструкция целевого объекта Далее находится метод экспорта exportObject. Основной метод заключается в вызове метода listen для создания serversocket и запуска потока для ожидания клиентских запросов. Пока что наш сервер запустил службу, ожидающую подключения клиента.клиент
Это на самом деле для создания прокси-объекта-заглушкиИспользуйте код для имитации основного процесса RMI следующим образом: Создайте новый объект пользователя
package com.llf.rmi;
public class User {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Напишите класс Skeleton для вызова клиентом [этот блок определяется rmi для защиты базовой сериализации и потокового соединения, здесь симуляция записывает базовую сериализацию и поток]
package com.llf.rmi;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
//server程序
public class User_Skeleton extends Thread {
private UserServer userServer;
public User_Skeleton(UserServer userServer) {
this.userServer = userServer;
}
public void run() {
ServerSocket serverSocket = null;
ObjectInputStream read = null;
ObjectOutputStream oos = null;
Socket socket=null;
try {
serverSocket = new ServerSocket(8888);
socket = serverSocket.accept();
while (socket != null) {
read = new ObjectInputStream(socket.getInputStream());
String method = (String) read.readObject();
if (method.equals("age")) {
int age = userServer.getAge();
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeInt(age);
oos.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (serverSocket != null) {
try {
oos.close();
read.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
написать заглушку
package com.llf.rmi;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class User_Stub extends User {
private Socket socket;
public User_Stub() {
try {
socket=new Socket("localhost", 8888);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public int getAge(){
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
try {
oos=new ObjectOutputStream(socket.getOutputStream());
oos.writeObject("age");
oos.flush();
ois=new ObjectInputStream(socket.getInputStream());
return ois.readInt();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
ois.close();
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return 0;
}
}
написать код сервера
package com.llf.rmi;
public class UserServer extends User{
public static void main(String[] args) {
UserServer server=new UserServer();
server.setAge(18);
//模拟rmi生成的skeleton代理对象
User_Skeleton user_Skeleton=new User_Skeleton(server);
user_Skeleton.start();
}
}
написать клиентский код
package com.llf.rmi;
public class UserClient {
public static void main(String[] args) {
User user=new User_Stub();
int age=user.getAge();
System.out.println(age);
}
}