使用rmi进行分布式开发,服务器注册一个rmi服务,而客户端通过访问rmi服务来完成相关业务。
而现在遇到的问题是,rmi服务运行在虚拟机上(虚拟机上有小网的ip 192.168.X.X,配置路由IP 10.62.X.X),客户端仅能通过路由IP连接服务器而不能通过小网IP连接服务器,这样该如何注册RMI服务?
如下所示:
用xshell连接到10.62.X.X的机器,运行ifconfig只能看到192.168.X.X的IP地址:
[c:\~]$
Connecting to 10.62.44.138:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.
Last login: Mon Mar 6 06:38:48 2017 from 10.62.100.97
[root@host-192-168-200-40 ~]# ifconfig
eth0 Link encap:Ethernet HWaddr FA:16:3E:AC:69:74
inet addr:192.168.200.40 Bcast:192.168.200.255 Mask:255.255.255.0
inet6 addr: fe80::f816:3eff:feac:6974/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:994873 errors:0 dropped:0 overruns:0 frame:0
TX packets:615654 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:131935665 (125.8 MiB) TX bytes:117107558 (111.6 MiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:8024568 errors:0 dropped:0 overruns:0 frame:0
TX packets:8024568 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:622160146 (593.3 MiB) TX bytes:622160146 (593.3 MiB)
[root@host-192-168-200-40 ~]#
================================================================================
参考了博客,大致了解了rmi的原理。
http://www.blogjava.net/freeman1984/archive/2014/12/05/421085.html
解决方案如下:
1. 统一使用小网ip或者回环IP127.0.0.1进行rmi服务注册
2. 编写一个类实现RMIClientSocketFactory指定使用路由IP创建socket连接
3. 客户端通过路由IP进行rmi远程方法调用
1. 统一使用小网ip或者回环IP127.0.0.1进行rmi服务注册
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import java.io.File;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class RmiServiceServer {
private static Logger dMsg = Logger.getLogger(RmiServiceServer.class);
private static Registry registry = null;
public static boolean startService(String connServerIP){
boolean isSucc = false;
try {
int port = 9000;
dMsg.info("start register agent service ...");
System.setProperty("java.rmi.server.hostname", connServerIP);
RemoteServiceImpl service = new RemoteServiceImpl();
String serverName = String.format("rmi://%s:%d/%s","127.0.0.1",port,"service");
try{
registry = LocateRegistry.createRegistry(port,new MyRMIClientSocketFactory(connServerIP,port), null);
Naming.rebind(serverName, service);
dMsg.info("succeed to register rmi service");
isSucc = true;
}catch (RemoteException e) {
dMsg.error("fail to register rmi service " + e.getMessage(),e);
}
} catch (MalformedURLException e) {
dMsg.error("fail to register rmi service " + e.getMessage(),e);
} catch (RemoteException e) {
dMsg.error("fail to register rmi service " + e.getMessage(),e);
}
return isSucc;
}
public static void stopService(){
dMsg.info("start to dispose service...");
try {
Registry registry = LocateRegistry.getRegistry(9000);
if(registry != null){
registry.unbind("service");
UnicastRemoteObject.unexportObject(registry, true);
}
} catch (RemoteException e1) {
dMsg.error("RemoteException error:");
dMsg.debug(e1.toString());
} catch (NotBoundException e) {
dMsg.error("service is ubinded.");
dMsg.debug(e.toString());
}
dMsg.info("finish to dispose service...");
}
public static void main(String[] args) {
initLog4J();
if(!startService(args[0])){
System.exit(0);
}
}
private static void initLog4J(){
String confPath = System.getProperty("user.dir") + File.separator + "conf";
String logConfigName = confPath + File.separator + "log4j.properties";
PropertyConfigurator.configure(logConfigName);
}
}
2. 编写一个类实现RMIClientSocketFactory执行使用路由IP创建socket连接
import java.io.IOException;
import java.io.Serializable;
import java.net.Socket;
import java.rmi.server.RMIClientSocketFactory;
public class MyRMIClientSocketFactory implements RMIClientSocketFactory,Serializable {
private static final long serialVersionUID = 8782346882801831839L;
private String host;
private int port;
public MyRMIClientSocketFactory(String host, int port) {
this.host = host;
this.port = port;
}
@Override
public Socket createSocket(String host, int port) throws IOException {
return new Socket(host,port);
}
}
3. 客户端通过路由IP进行rmi远程方法调用
import org.apache.log4j.Logger;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
public class RmiServiceClient {
private static Logger dMsg = Logger.getLogger(RmiServiceClient.class);
public static boolean connectService(String host,String port,String serviceName){
boolean isConnected = false;
String url = "rmi://"+host+":"+port+"/"+serviceName;
dMsg.info("service url is:"+url);
try {
Remote remote = Naming.lookup(url);
if(remote instanceof RemoteService){
dMsg.debug("start call service...");
RemoteService service = (RemoteService) remote;
dMsg.debug("test print:" + service.print());
}
dMsg.debug("call service finished.");
isConnected = true;
} catch (MalformedURLException e) {
dMsg.error("cannot parse url:");
dMsg.debug(e.toString());
} catch (RemoteException e) {
dMsg.error("connect error:");
dMsg.debug(e.toString());
} catch (NotBoundException e) {
dMsg.error("cannot found service:");
dMsg.debug(e.toString());
}
return isConnected;
}
public static void inputTips(){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
boolean flag = true;
while(flag){
try {
dMsg.debug("Please input hostip:");
String host = br.readLine();
dMsg.debug("Please input service port:");
String port = br.readLine();
dMsg.debug("Please input service name:");
String serviceName = br.readLine();
if(connectService(host, port, serviceName)){
flag = false;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
initLog4J();
inputTips();
}
}private static void initLog4J(){ String confPath = System.getProperty("user.dir") + File.separator + "conf"; String logConfigName = confPath + File.separator + "log4j.properties"; PropertyConfigurator.configure(logConfigName); }