JavaDemo——java的RMI远程调用

本文详细介绍RMI(远程方法调用)的实现步骤,包括定义远程接口、服务端实现、服务注册及客户端调用过程。通过具体示例,演示如何解决常见问题,如异常处理、端口设置和跨机器通信。

结构:

1.定义一个继承Remote类的接口(服务端和客户端一致):

/**
 * 2019年7月1日下午2:25:15
 */
package testrmiserver.remoteobject;

import java.rmi.Remote;
import java.rmi.RemoteException;

/**
 * @author XWF
 *
 */
public interface IRemoteObj extends Remote {

	public int getStrLen(String str) throws RemoteException;//需要抛异常,实现类继承的UnicastRemoteObject构造方法抛异常
	
}

2.服务端实现接口:

/**
 * 2019年7月1日下午2:28:20
 */
package testrmiserver.remoteobject;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

/**
 * @author XWF
 *
 */
public class RemoteObjImpl extends UnicastRemoteObject implements IRemoteObj {

	public RemoteObjImpl() throws RemoteException {
		super();
	}

	@Override
	public int getStrLen(String str) throws RemoteException {
		System.out.println("收到调用,str=" + str);
		return str == null ? -1 : str.length();
	}

}

3.服务端:

/**
 * 2019年7月1日下午2:24:01
 */
package testrmiserver;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RMISocketFactory;
import java.util.Arrays;

import testrmiserver.remoteobject.IRemoteObj;
import testrmiserver.remoteobject.RemoteObjImpl;

/**
 * @author XWF
 *
 */
public class TestRmiServer {
	
	private static int registryPort = 9999;//服务端注册端口
	private static int serverPort = 1234;//服务端服务端口

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			System.out.println("开始服务端");
			//指定服务端口
			RMISocketFactory.setSocketFactory(new RMISocketFactory() {
				@Override
				public Socket createSocket(String host, int port) throws IOException {
					System.out.println("createSocket, host=" + host + ",port=" + port);
					return new Socket(host, port);
				}
				@Override
				public ServerSocket createServerSocket(int port) throws IOException {
					if(port == 0) {
						port = TestRmiServer.serverPort;//服务端口
					}
					System.out.println("createServerSocket,port=" + port);
					return new ServerSocket(port);
				}
			});
			
			//注册端口
			Registry r = LocateRegistry.createRegistry(TestRmiServer.registryPort);
			System.out.println("----");
			System.setProperty("java.rmi.server.hostname", "127.0.0.1");//创建服务端口时会用hostname,不要使用localhost或者127.0.0.1,客户端创建对应的端口时也会使用该值
			IRemoteObj obj = new RemoteObjImpl(); 
			Naming.bind("rmi://192.168.1.30:9999/testrmi", obj);
//			Naming.bind("rmi://192.168.1.30:9999/testrmi", obj);//bind不能重复绑定name
			Naming.bind("rmi://192.168.1.30:9999/A", obj);//bind不同name可以绑定同一个obj
			Naming.rebind("rmi://192.168.1.30:9999/testrmi", obj);//重复绑定用rebind
			System.out.println(Arrays.asList(r.list()));
			System.out.println("服务端启动完毕");
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (AlreadyBoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

4.客户端:

/**
 * 2019年7月1日下午2:29:32
 */
package testrmiclient;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.RMISocketFactory;

import testrmiserver.remoteobject.IRemoteObj;

/**
 * @author XWF
 *
 */
public class TestRmiClient {
	
	private static int registryPort = 9999;//服务端注册端口
	private static int serverPort = 1234;//服务端服务端口
	
	private static int forRegistryPort = 8888;//客户端对接注册端口
	private static int clientPort = 4321;//客户端对接服务端口

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			System.out.println("远程调用");
			RMISocketFactory.setSocketFactory(new RMISocketFactory() {
				//失败会三次重试
				@Override
				public Socket createSocket(String host, int port) throws IOException {
					System.out.println("createSocket, host=" + host + ",port=" + port);
					Socket s = new Socket();
					if(port == TestRmiClient.registryPort) {
						s.bind(new InetSocketAddress(TestRmiClient.forRegistryPort));
					}else if(port == TestRmiClient.serverPort) {
						s.bind(new InetSocketAddress(TestRmiClient.clientPort));
					}
					s.connect(new InetSocketAddress(host, port));
					System.out.println(s.getLocalSocketAddress().toString());
					System.out.println(s.getRemoteSocketAddress().toString());
					return s;
				}
				@Override
				public ServerSocket createServerSocket(int port) throws IOException {
					System.out.println("createServerSocket,port=" + port);
					return new ServerSocket(port);
				}
			});
			IRemoteObj obj = (IRemoteObj) Naming.lookup("rmi://192.168.1.30:9999/testrmi");
			System.out.println("len:" + obj.getStrLen("hello"));
			for(int i = 1; i <= 10; i++) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("hello" + i + " len:" + obj.getStrLen("hello" + i));
			}
		} catch (MalformedURLException | RemoteException | NotBoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

运行结果:

注意事项:

1.接口里的远程方法需要抛出RemoteException异常,服务端的实现类继承了UnicastRemoteObject类,该类构造方法抛出异常,实现类构造方法也要有;

2.服务端和客户端的接口要保持一致(包括包名也要一致);

3.Naming的bind方法不要重复绑定相同name值,需要用rebind重新绑定;

4.System.setProperty的hostname不要用localhost或者127.0.0.1,主要是客户端对接服务器服务端口时使用了该值,客户端和服务端通常不是在一台机器上;

否则客户端会出下面这种异常:

 

 

参考:

https://blog.youkuaiyun.com/5iasp/article/details/8707596

https://blog.youkuaiyun.com/lmy86263/article/details/72594760

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值