RMI框架解析二

RMI框架解析二

远程方法中的参数返回值的传递:

当客户端调用服务器端的远程对象的方法时,客户端会向服务器端传递传递参数,服务器端则会根据客户端传递的返回值。

RMI规范对参数以及返回值的传递作了以下规定:

1). 只哟基本类型的数据、远程对象以及可序列化的对象才可以作为参数或返回值进行传递。

如果参数或返回值是一个远程对象,那么把它的存根对象传递到接收方,也就是说,接收方得到的是远程对象的存根对象。

如果参数或返回值是可序列化的对象,那么直接传递该对象序列化数据。也就是说,接收方,接收方得到的是发送方的可序列化的对象的复制品

如果参数或返回值是基本类型的数据,那么直接传递该数据的序列化的数据,也就是说,接收方得到是发送方的基本类型的复制品

回调客户端的远程对象

远程对象不仅可以位于服务器端,也可以位于客户端。

只要服务器端获得了客户端的远程对象的存根对象,服务器端也能调用客户端的远程对象的方法,这种调用过程称为回调

在股票报价系统中,服务器端不断地把最新的股票价格发送到客户端,并且在客户端的界面上显示出来。客户端有一个StockQuote远程对象,它的quote(String stockSymbol, double price)方法在客户端的界面上打印参数指定的股票的价格。服务器端有一个StockQuoteRegistry远程对象,它能调用客户端的StockQuote远程对象的quote()方法。

SimpleClient类的main()方法先通过注册表获得StockQuoteRegistryImpl远程对象的存根对象,因此RMI框架会把这个远程对象的存根对象发送到服务器端,使得服务器端的StockQuoteRegistryImpl远程对象的缓存中保存了这个存根对象。

 

 

package com.unmi.reback;

 

import java.rmi.*;

public interface StockQuoteRegistry extends Remote{

  public void registerClient(StockQuote client)throws RemoteException;

  public void unregisterClient(StockQuote client)throws RemoteException;

}

 

package com.unmi.reback;

 

import java.rmi.*;

import java.rmi.server.*;

import java.util.*;

 

public class StockQuoteRegistryImpl extends UnicastRemoteObject

           implements StockQuoteRegistry, Runnable{

 

    private static final long serialVersionUID = 1L;

    protected HashSet<StockQuote> clients;

 

  public StockQuoteRegistryImpl()throws RemoteException{

        clients = new HashSet<StockQuote>();

  }

 

  public void run(){

    //创建一些股票代号

    String[] symbols = new String[] {"SUNW", "MSFT", "DAL", "WUTK", "SAMY", "KATY"};

    Random rand = new Random();

 

    double values[] = new double[symbols.length];

 

    //为每个股票分配任意价格

    for(int i=0; i < values.length; i++){

      values[i] = 25.0 + rand.nextInt(100);

    }

 

    for (;;){

      //随机取出一个股票

      int sym = rand.nextInt(symbols.length);

 

      // 修改股票的价格

      int change = 100 - rand.nextInt(201);

      values[sym] = values[sym] + ((double) change) / 100.0;

      if (values[sym] < 0) values[sym] = 0.01;

 

      Iterator<StockQuote> iter = clients.iterator();

      while (iter.hasNext()){

        StockQuote client =  iter.next();

        try{

          client.quote(symbols[sym], values[sym]);

        }catch (Exception exc){

           System.out.println("删除一个无效的客户");

           iter.remove();

        }

      }

 

      try { Thread.sleep(1000); } catch (Exception ignore) {}

    }

  }

 

  public void registerClient(StockQuote client)throws RemoteException{

    System.out.println("加入一个客户");

    clients.add(client);

  }

 

  public void unregisterClient(StockQuote client)throws RemoteException{

    System.out.println("删除一个客户");

    clients.remove(client);

  }

}

 

package com.unmi.reback;

import java.rmi.registry.LocateRegistry;

import javax.naming.*

public class SimpleServer{

  public static void main( String args[] ){

    try{

    LocateRegistry.createRegistry(1099);

    StockQuoteRegistryImpl registry=new StockQuoteRegistryImpl();

 

       Context namingContext=new InitialContext();

       namingContext.rebind( "rmi:StockQuoteRegistry", registry);

       System.out.println( "服务器注册了一个StockQuoteRegistry对象" );

 

       new Thread(registry).start();

    }catch(Exception e){

       e.printStackTrace();

    }

  }

}

 

package com.unmi.reback;

import java.rmi.*;

/** 客户端的远程对象接口 */

public interface StockQuote extends Remote{

    public void quote(String stockSymbol, double price)throws RemoteException;

}

 

 

package com.unmi.reback;

 

import java.rmi.*;

import java.rmi.server.*;

 

public class StockQuoteImpl extends UnicastRemoteObject

                                      implements StockQuote{

  public StockQuoteImpl()throws RemoteException{}

 

  public void quote(String symbol, double value)throws RemoteException{

    System.out.println(symbol+": "+value);

  }

}

     

package com.unmi.reback;

import javax.naming.*;

 

public class SimpleClient{

 

  public static void main( String args[] ){

    String url="rmi://localhost/";

    try{

      Context namingContext=new InitialContext();

      StockQuoteRegistry registry=(StockQuoteRegistry)namingContext.lookup(url+"StockQuoteRegistry");

     

      StockQuote client=new StockQuoteImpl();

      registry.registerClient(client);   

 

    }catch( Exception e){

       e.printStackTrace();

    }

  }

}      

 

远程对象的并发访问:

RMI框架允许远程对象被客户端并发访问,远程对象在本身的实现中必须保证是线程安全的,即当远程对象被多个客户端同时访问时,不会出现对共享资源的竞争。

如下:在两个客户进程中,都有若干生产者线程和消费者线程,它们都访问服务器端的同一个堆栈Stack远程对象。生产者线程远程调用Stack对象的push()方法,向堆栈中放入产品,消费者线程使用Stack对象的pop()方法从堆栈中取出产品。

 

客户进程生产者

 

服务器进程

Stack

客户进程消费者

 

 

 

 

 

 

 

 

 

 

 


package com.unmi.syn;

 

import java.io.Serializable;

 

public class Apple  implements Serializable{

   

    private static final long serialVersionUID = 1L;

   

    private int id;

 

    public int getId() {

       return id;

    }

 

    public void setId(int id) {

       this.id = id;

    }

 

}

 

 

package com.unmi.syn;

 

import java.rmi.Remote;

import java.rmi.RemoteException;

 

public interface Pool extends Remote {

   

    public Apple get() throws RemoteException;

   

    public void put(Apple apple) throws RemoteException;

   

 

}

package com.unmi.syn;

 

import java.rmi.RemoteException;

import java.rmi.server.UnicastRemoteObject;

import java.util.ArrayList;

import java.util.List;

 

public class PoolImpl extends UnicastRemoteObject implements Pool {

   

    private static final long serialVersionUID = 1L;

   

    private List<Apple> pools;

   

    public PoolImpl() throws RemoteException {

       pools = new ArrayList<Apple>();

    }

 

    public synchronized Apple get() throws RemoteException {

       while (pools.isEmpty()) {

           try {

              this.wait();

           } catch (InterruptedException e) {

              e.printStackTrace();

           }

       }

       Apple apple = pools.remove(0);

       this.notify();

       return apple;

    }

 

    public synchronized void put(Apple apple) throws RemoteException {

       while (pools.size() >= 5) {

           try {

              this.wait();

           } catch (InterruptedException e) {

              e.printStackTrace();

           }

       }

       pools.add(apple);

       this.notify();

    }

 

}

 

package com.unmi.syn;

 

import java.rmi.registry.LocateRegistry;

 

import javax.naming.InitialContext;

 

public class Server {

   

    public static void main(String[] args) {

       try {

           LocateRegistry.createRegistry(1099);

          

           InitialContext ctx = new InitialContext();

          

           ctx.bind("rmi:pool", new PoolImpl());

          

           System.out.println("server ready:");

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

 

}

 

package com.unmi.syn;

 

import java.rmi.RemoteException;

 

public class Consumer implements Runnable {

 

    private Pool pool;

   

    public Consumer(Pool pool) {

       this.pool = pool;

    }

   

    public void run() {

       try {

           Apple apple = pool.get();

           System.out.println("consume: " + apple.getId());

       } catch (RemoteException e) {

           e.printStackTrace();

       }

    }

}

 

package com.unmi.syn;

 

import java.rmi.RemoteException;

 

public class Producer implements Runnable {

   

    private Pool pool;

   

    private int j = 0;

   

    public Producer(Pool pool) {

       this.pool = pool;

    }

   

    public void run() {

       try {

           Apple apple = new Apple();

           apple.setId(j++);

           pool.put(apple);

           System.out.println("produce: " + apple.getId());

       } catch (RemoteException e) {

           e.printStackTrace();

       }

    }

}

 

 

package com.unmi.syn;

 

import javax.naming.InitialContext;

 

public class Client {

    public static void main(String[] args) throws Exception {

      

       InitialContext namingContext = new InitialContext();

      

       Pool pool = (Pool)namingContext.lookup("rmi://localhost/pool");

      

       Producer p = new Producer(pool);

      

       for (int i=0; i<5; i++) {

           new Thread(p).start();

       }

      

       Consumer c = new Consumer(pool);

      

       for (int i=0; i<5; i++) {

           new Thread(c).start();

       }

      

      

    }

   

   

 

}

 

 

 

阅读更多
个人分类: EJB 分布式开发
上一篇RMI框架解析一
下一篇对象的序列化与反序列化
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭