RMI远程调用时的内外网端口映射问题(RMI远程调用如何穿透防火墙)

转载自:http://www.juuluu.org/html/softDoc/2011/10/19/09/45/wtpnkjxlwt.html


以下是一个RMI项目的实施笔记:

环境:防火墙(XX卫士)   外网IP:x.x.x.135 port:8400/8500   内网IP: x.x.x.90 port:8400/8500

                                  内外网IP及port互相映射. (外网IP是设定的防火墙上的,管理员进行映射配置)

 

1.RMI远程调用的服务注册到:内网的8400端口上 (不用创建stub/skeleton,不使用缺省的1099)

  //LocateRegistry.createRegistry(rmiServerPort); //定义服务注册与查找服务端口 8400

2.RMI远程调用的数据通信端口绑定到:内网的8500端口上

   // RMISocketFactory.setSocketFactory(new SMRMISocket());  //定义数据传输端口 8500

3.设定访问外网:x.x.x.135:8400时穿透防火墙访问内网:x.x.x.90:8400

  //在sun.rmi.server.UnicastRef调用时的服务IP为:x.x.x.135,而不是x.x.x.90(客户的本地不存在RMI服务嘛)

  //System.setProperty("java.rmi.server.hostname","x.x.x.135"); 

 

4.RMI调用穿透防火墙不是自动的,需要我们手工指定,就如3所指,如果不加设定,在互联网上就不能通过外网IP访问内网IP上绑定的RMI服务

 

5.通过本项目,明白了RMI可以不用rmic创建stub/skeleton的,也可以不用启动rmiRegistry而通过程序直接启动RMI服务,这样方便了代码的修改与项目的实施.

 

由于是项目代码,所以不打包上传代码了。简写如下:

///RMI服务端代码

    String hostIP = InetAddress.getLocalHost().getHostAddress();
      int rmiServerPort = 8400;  //数据传输服务为8400
      String bindName = "licenseServer";
       //下面这行代码不能少,否则当路由器x.x.x.135映射到的内网IP:x.x.x.90时,
       //访问RMI服务时将导向本地的x.x.x.90,那么客户端就是访问本地x.x.x.90,
       //这绝对错误.服务是在公网路由器(含公共IP)的后面,不在客户的本地
       System.setProperty("java.rmi.server.hostname","x.x.x.135");
      try {
        RMISocketFactory.setSocketFactory(new SMRMISocket());  //定义数据传输端口 8500
        LocateRegistry.createRegistry(rmiServerPort); //定义服务注册与查找服务端口 8400
      }
      catch (Exception ex) {
        System.out.println("服务器端口绑定时发生错误:"+ex.getMessage());
        ex.printStackTrace();
      }
      //创建license生成器的服务对象
      MakeLicense licenseService = new MakeLicenseService();
      //绑定一个服务对象到一个服务端口
      //URL format (without the scheme component)
      String bindUrl = "//"+hostIP+":"+ rmiServerPort +"/"+bindName;
      Naming.rebind(bindUrl, licenseService);
      System.out.println(bindUrl+" server is ready.");

 

SMRMISocket.java

import java.rmi.server.*;
import java.io.*;
import java.net.*;

public class SMRMISocket
    extends RMISocketFactory {

  public Socket createSocket(String host, int port) throws IOException {
    return new Socket(host, port);
  }

  public ServerSocket createServerSocket(int port) throws IOException {
    if (port == 0)
      port = 8500;

    System.out.println("RMI服务器的注册与数据传输端口 ="+port);
    return new ServerSocket(port);
  }

}

客户端代码:

private String remoteHost = "x.x.x.135";   //公网IP或局域网IP
  private int rmiServerPort=8400;  //查找服务端口 8400
  private String bindName = "licenseServer";   //RMI服务名称
  private int revCount = 0;
  private MakeLicense remoteObject=null;
  public LicenseRequestClient()  {
    try{
//      if(System.getSecurityManager()==null){
//        System.setSecurityManager(new RMISecurityManager());
//      }
      String bindUrl = "//"+remoteHost+":"+ rmiServerPort +"/"+bindName;
      System.out.println("请求的远程服务URL="+bindUrl);
      MakeLicense remoteObject = (MakeLicense) Naming.lookup(bindUrl);
      this.remoteObject = remoteObject;
//      System.out.print("远程remoteObject="+remoteObject);
    }
    catch (RemoteException re) {
      System.out.println("RemoteException:" + re);
    }
    catch (NotBoundException nbe) {
      System.out.println("NotBoundException:" + nbe);
    }
    catch (MalformedURLException mfe) {
      System.out.println("MalformedURLException:" + mfe);
    }
  }



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值