RMI应用过程中的问题


最近闲来无事补充了下自己的短板,学习了下RMI,本来以为很简单的事,没想到遇到几个问题还是花了一段时间,在这记录下,测试demo代码附在后面。

RMI的原理在这不说了,百度或Google很多,只说下遇到的问题,具体问题解决方法我这说的不清楚也可以Google下。

说明:Centos6是装载VMware虚拟机中的固定IP,防火墙开,网络适配器为桥接模式;Windows10;registry port :1234;socket port:12345(开始不知道有这种端口)。

1、Server和Client运行环境都是Windows,单网卡多网卡运行都正常。

2、Server运行环境都是Windows,Client运行环境是Centos6,单网卡,运行正常。

3、Server运行环境都是Windows,Client运行环境是Centos6,多网卡,运行不正常;

原因:Server运行时使用的ip和Linux使用的ip不在同一个网段下,解决方法:指定Server的hostname:java.rmi.server.hostname=要绑定的ip

4、Server运行环境是Centos6,Client运行环境是Centos6或Windows,运行不正常;

    ①注册端口1234没有放开,报

java.rmi.ConnectIOException: Exception creating connection to: 192.168.1.16; nested exception is:
        java.net.NoRouteToHostException: No route to host (Host unreachable)

或java.rmi.ConnectException: Connection refused to host: 192.168.1.16; nested exception is:
        java.net.ConnectException: Connection timed out: connect;服务器开放端口1234;

②服务器端没有指定hostname,java.rmi.server.hostname=服务器的ip或者机器名,如果指定是机器名的话需要将机器名对应的ip写入在Client的hosts文件里。可以指定-D 或catalina_Opts或代码中加入System.setProperty("java.rmi.server.hostname", "服务器的ip或者机器名")

③数据传输Socket端口12345没有开放,放开12345端口即可。根据错误日志,可以看出Client和Server也是通过Socket来传输数据的。此处Socket端口默认是随机的,每次服务端启动时端口可能是变化的,所以如果防火墙启动的话最好在代码中指定。主要在这花的时间比较长,因为根据异常从网上找的信息大多是指定hostname,就一直在这纠结了。关闭防火墙后好使,根据netstat命令一看果然两个端口。还是对RMI内部机制不熟悉导致。

异常信息:

java.rmi.ConnectException: Connection refused to host: 192.168.1.16; nested exception is:
        java.net.ConnectException: Connection timed out: connect
        at sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)
        at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
        at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
        at sun.rmi.server.UnicastRef.invoke(Unknown Source)
        at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
        at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
        at com.sun.proxy.$Proxy0.sayHello(Unknown Source)
        at com.springmvc.rmi.RMIClient.main(RMIClient.java:18)
Caused by: java.net.ConnectException: Connection timed out: connect
        at java.net.DualStackPlainSocketImpl.connect0(Native Method)
        at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
        at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
        at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
        at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
        at java.net.PlainSocketImpl.connect(Unknown Source)
        at java.net.SocksSocketImpl.connect(Unknown Source)
        at java.net.Socket.connect(Unknown Source)
        at java.net.Socket.connect(Unknown Source)
        at java.net.Socket.<init>(Unknown Source)
        at java.net.Socket.<init>(Unknown Source)

        at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(Unknown Source)
        at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(Unknown Source)
        ... 8 more


解决以上问题后:

Server端:

[root@localhost Desktop]# java -jar -Djava.rmi.server.hostname=rmi rmiserver.jar
输入ip(localhost输入1):
1
rmi://localhost:1234/irmi
>>>>>>远程RMI绑定成功

Client端:

[root@rmi demo]# java -jar rmiclient.jar
输入ip:
192.168.1.16
和服务器说点话:
你好
ip:192.168.1.15-->client:你好,给你7

Server端:

[root@localhost Desktop]# java -jar -Djava.rmi.server.hostname=rmi rmiserver.jar
输入ip(localhost输入1):
1
rmi://localhost:1234/irmi
>>>>>>远程RMI绑定成功
host:192.168.1.15
ip:192.168.1.15-->welcome:你好


OK!


以下是测试Demo代码:

Client:

package com.springmvc.rmi;

import java.io.IOException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.util.Scanner;

public class RMIClient {
    public static String url = "rmi://%s:1234/irmi";

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        try {
            System.out.println("输入服务器ip:");
            url = String.format(url, s.next());
            IRMIInterface irmi = (IRMIInterface) Naming.lookup(url);
            System.out.println("和服务器说点话:");
            irmi.sayHello(s.next());
            System.out.println(irmi.getSomeThing("client"));
        } catch (NotBoundException | IOException e) {
            e.printStackTrace();
        } finally {
            s.close();
        }
    }
}

Server:

package com.springmvc.rmi;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.RMISocketFactory;
import java.rmi.server.ServerNotActiveException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Scanner;

/**
 * 服务器端
 *                       
 * @Filename: RMIServer.java
 * @Version: 1.0
 * @Author: yanrp
 * @Email: 
 *
 */
public class RMIServer extends UnicastRemoteObject implements IRMIInterface {
    public static String      url              = "rmi://%s:1234/irmi";
    /**
     *Comment for <code>serialVersionUID</code>
     */
    private static final long serialVersionUID = -7279580357318512456L;

    protected RMIServer() throws RemoteException {
        super();
    }

    @Override
    public void sayHello(String name) throws RemoteException {
        try {
            String host = getClientHost();
            String ip = InetAddress.getByName(host).getHostAddress();
            System.out.println("host:" + host);
            System.out.println("ip:" + ip + "-->welcome:" + name);
        } catch (ServerNotActiveException | UnknownHostException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getSomeThing(String name) throws RemoteException {
        String ret = "";
        try {
            String ip = InetAddress.getByName(getClientHost()).getHostAddress();
            ret = "ip:" + ip + "-->" + name + ":你好,给你" + (int) (Math.random() * 100);
        } catch (UnknownHostException | ServerNotActiveException e) {
            e.printStackTrace();
        }
        return ret;
    }

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        try {
            System.out.println("输入ip(localhost输入1):");
            String ip = s.next();
            if ("1".equals(ip)) {
                ip = "localhost";
            }
            url = String.format(url, ip);
            System.out.println(url);
            //System.setProperty("java.rmi.server.hostname", "192.168.1.15");
            CustomRMISocketFactory socketFactory = new CustomRMISocketFactory(12345);
            RMISocketFactory.setSocketFactory(socketFactory);
            IRMIInterface irmi = new RMIServer();
            LocateRegistry.createRegistry(1234);
            Naming.bind(url, irmi);
            System.out.println(">>>>>>远程RMI绑定成功");
        } catch (AlreadyBoundException | IOException e) {
            e.printStackTrace();
        } finally {
            s.close();
        }
    }
}

/**
 * SocketFactory 指定Socket端口工厂类
 *                       
 * @Filename: RMIServer.java
 * @Version: 1.0
 * @Author: yanrp
 * @Email: 
 *
 */
class CustomRMISocketFactory extends RMISocketFactory {
    private int p;

    CustomRMISocketFactory(int port) {
        this.p = port;
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException {
        if (port == 0) port = this.p;
        return new Socket(host, port);
    }

    @Override
    public ServerSocket createServerSocket(int port) throws IOException {
        if (port == 0) port = this.p;
        return new ServerSocket(port);
    }

}

Interface:
package com.springmvc.rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;
/**
 * 开放接口
 *                       
 * @Filename: IRMIInterface.java
 * @Version: 1.0
 * @Author: yanrp 
 * @Email: 
 *
 */
public interface IRMIInterface extends Remote {
    void sayHello(String name) throws RemoteException;

    String getSomeThing(String name) throws RemoteException;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值