使用Mina实现RPC调用,消息通知,广播。

来源:互联网 发布:专门看电影的软件 编辑:程序博客网 时间:2024/06/08 12:08
在上一篇的基础上,增强功能。
common包,定义通用接口,和传递中使用的对象,对象需要实现序列化接口。
接口:
  1. package mina.common;
  2. public interface RpcInterface {
  3.     public String getStringValue(String arg0,int arg1,Apple arg2);
  4.     public int getIntValue();
  5.     public void printPrice();
  6. }
bean类,定义了一只苹果。
  1. package mina.common;

  2. import java.awt.Color;
  3. import java.io.Serializable;
  4. import java.util.Date;

  5. public class Apple implements Serializable{

  6.     private Color color = Color.BLACK;
  7.     private double weight = 1.1;
  8.     private double dia = 2.33;
  9.     
  10.     private int num = 3;
  11.     private String name = "aaapple";
  12.     
  13.     private Date pdate = new Date();
  14.     
  15.     public Date getPdate() {
  16.         return pdate;
  17.     }
  18.     public void setPdate(Date pdate) {
  19.         this.pdate = pdate;
  20.     }
  21.     public Color getColor() {
  22.         return color;
  23.     }
  24.     public void setColor(Color color) {
  25.         this.color = color;
  26.     }
  27.     public double getDia() {
  28.         return dia;
  29.     }
  30.     public void setDia(double dia) {
  31.         this.dia = dia;
  32.     }
  33.     public String getName() {
  34.         return name;
  35.     }
  36.     public void setName(String name) {
  37.         this.name = name;
  38.     }
  39.     public int getNum() {
  40.         return num;
  41.     }
  42.     public void setNum(int num) {
  43.         this.num = num;
  44.     }
  45.     public double getWeight() {
  46.         return weight;
  47.     }
  48.     public void setWeight(double weight) {
  49.         this.weight = weight;
  50.     }
  51. }
server包,
Server类,启动监听,
  1. package mina.server;

  2. import java.net.InetSocketAddress;

  3. import org.apache.mina.common.DefaultIoFilterChainBuilder;
  4. import org.apache.mina.common.IoAcceptor;
  5. import org.apache.mina.common.IoAcceptorConfig;
  6. import org.apache.mina.transport.socket.nio.SocketAcceptor;
  7. import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;
  8. import org.apache.mina.transport.socket.nio.SocketSessionConfig;

  9. public class Server {

  10.     /** Choose your favorite port number. */
  11.     private static final int PORT = 8080;

  12.     private static final boolean USE_SSL = false;

  13.     public static void main(String[] args) throws Exception {
  14.         IoAcceptor acceptor = new SocketAcceptor();
  15.         IoAcceptorConfig config = new SocketAcceptorConfig();
  16.         DefaultIoFilterChainBuilder chain = config.getFilterChain();

  17.         ((SocketSessionConfig) config.getSessionConfig()).setReuseAddress(true);
  18.         // Add SSL filter if SSL is enabled.
  19.         if (USE_SSL) {
  20.             // addSSLSupport(chain);
  21.         }

  22.         // Bind
  23.         acceptor.bind(new InetSocketAddress(PORT), new ServerHandler(), config);

  24.         System.out.println("Listening on port " + PORT);
  25.     }
  26. }
RpcServerImpl实现类,实现common包中定义的接口,实际的处理的地方。
  1. package mina.server;

  2. import mina.common.Apple;
  3. import mina.common.RpcInterface;

  4. public class RpcServerImpl implements RpcInterface {

  5.     public String getStringValue(String arg0,int arg1,Apple arg2) {
  6.         System.out.println("apple time is "+arg2.getPdate());
  7.         return "this is sign from server.";
  8.     }

  9.     public int getIntValue() {
  10.         return 3;
  11.     }

  12.     public void printPrice() {
  13.         System.out.println("******price**********");
  14.         System.out.println("$10000000000000000000");
  15.         System.out.println("*********************");
  16.     }
  17. }
ServerHandler类,处理客户端连接事务,和客户端通信处理的类。
  1. package mina.server;

  2. import java.io.InputStream;
  3. import java.io.OutputStream;
  4. import java.lang.reflect.InvocationTargetException;
  5. import java.lang.reflect.Method;
  6. import java.net.SocketAddress;
  7. import java.util.ArrayList;
  8. import java.util.Enumeration;
  9. import java.util.Hashtable;
  10. import java.util.Iterator;
  11. import java.util.List;
  12. import java.util.Properties;

  13. import org.apache.mina.common.ByteBuffer;
  14. import org.apache.mina.common.IoSession;
  15. import org.apache.mina.handler.StreamIoHandler;
  16. import org.apache.mina.integration.jmx.IoSessionManager;

  17. public class ServerHandler extends StreamIoHandler {

  18.     Hashtable sessionMgr = new Hashtable();
  19.     List serverList = new ArrayList();
  20.     ServerHandler() {
  21.         serverList.add(new RpcServerImpl());
  22.     }

  23.     public void messageReceived(IoSession session, Object buf) {
  24.         SocketAddress adr = session.getRemoteAddress();
  25.         System.out.println("remote address is =" + adr.toString());
  26.         System.out.println("buf=" + buf.toString());
  27.         if (buf instanceof ByteBuffer) {
  28.             ByteBuffer bb = (ByteBuffer) buf;
  29.             System.out.println("bbb===" + bb);
  30.             try {
  31.                 Properties prop = (Properties) bb.getObject();
  32.                 System.out.println("prop==" + prop);

  33.                 String interfaceName = (String) prop.get("interface");
  34.                 Iterator it = serverList.iterator();
  35.                 while (it.hasNext()) {// 查找实例
  36.                     Object serobj = it.next();
  37.                     Class[] clazz = serobj.getClass().getInterfaces();
  38.                     if (isContains(clazz, interfaceName)) {// 找到相应实例
  39.                         System.out.println("find.." + interfaceName);
  40.                         int argc = Integer.parseInt(String.valueOf(prop
  41.                                 .get("argc")));
  42.                         Class[] types = null;// 参数类型数组
  43.                         Object[] args = null;// 参数对象数组

  44. //                       不为最大值时表示有正常参数,否则为无参数。
  45.                         if (argc != Integer.MAX_VALUE) {
  46.                             // 重组参数列表
  47.                             types = new Class[argc];
  48.                             args = new Object[argc];
  49.                             List typeList = (List) prop.get("types");
  50.                             List argList = (List) prop.get("args");
  51.                             for (int i = 0; i < argc; i++) {
  52.                                 args[i] = argList.get(i);
  53.                                 types[i] = (Class) typeList.get(i);
  54.                                 System.out.println("arg###=" + args[i]
  55.                                         + "   type@@@=" + types[i]);
  56.                             }
  57.                         }
  58.                         String methodName = prop.getProperty("method");

  59.                         Method method = serobj.getClass().getMethod(methodName,
  60.                                 types);
  61.                         //调用
  62.                         Object resultObject = method.invoke(serobj, args);

  63.                         //回复
  64.                         replyCall(session.getRemoteAddress().toString(),resultObject);
  65.                     }
  66.                 }
  67.             } catch (Exception e) {
  68.                 e.printStackTrace();
  69.             }
  70.         }
  71.     }
  72.     
  73.     //广播操作,广播消息或事件.标记为"BROADCAST" 
  74.     public void brocastMessage(Object obj){
  75.         Enumeration enu = sessionMgr.keys();
  76.         while (enu.hasMoreElements()) {
  77.             String addr = (String) enu.nextElement();
  78.             sendMessage("BROADCAST",addr,obj);
  79.         }
  80.     }
  81.     
  82.     //通知操作,通知消息或事件。标记为"NOTIFY"
  83.     public void notify(String addr,Object obj){
  84.         sendMessage("NOTIFY",addr,obj);
  85.     }
  86.     
  87.     //响应RPC调用。
  88.     public void replyCall(String addr,Object obj){
  89.         sendMessage("REPLYCALL",addr,obj);
  90.     }
  91.     
  92.     private void sendMessage(String mark,String addr,Object obj){
  93.         Object sessionObj = sessionMgr.get(addr);
  94.         if(sessionObj!=null){
  95.             IoSession session = (IoSession)sessionObj;
  96.             if(!session.isConnected()){
  97.                 return;
  98.             }
  99.             Properties resultProp = new Properties();
  100.             resultProp.setProperty("mark",mark);
  101.             if(obj!=null//对于无返回的情况。
  102.                 resultProp.put("Object",obj);
  103.             ByteBuffer bb = ByteBuffer.allocate(16);
  104.             bb.setAutoExpand(true);
  105.             bb.putObject(resultProp);
  106.             bb.flip();
  107.             session.write(bb);
  108.         }else{
  109.             System.out.println("session null.addr="+addr);
  110.         }
  111.     }
  112.     
  113.     protected void processStreamIo(IoSession session, InputStream ins,
  114.             OutputStream ous) {
  115.         System.out.println("processStreamIo is called.");
  116.     }

  117.     private boolean isContains(Class[] clazz, String ifName) {
  118.         for (int i = 0; i < clazz.length; i++) {
  119.             if (clazz[i].getName().equals(ifName))
  120.                 return true;
  121.         }
  122.         return false;
  123.     }

  124.     public void sessionOpened(IoSession ssn) {
  125.         System.out.println("session open for " + ssn.getRemoteAddress());
  126.         sessionMgr.put(ssn.getRemoteAddress().toString(),ssn);
  127.     }

  128.     public void exceptionCaught(IoSession ssn, Throwable cause) {
  129.         cause.printStackTrace();
  130.         sessionMgr.remove(ssn.getRemoteAddress().toString());
  131.         ssn.close();
  132.     }

  133.     public void sessionClosed(IoSession ssn) throws Exception {
  134.         System.out.println("session closed from " + ssn.getRemoteAddress());
  135.         sessionMgr.remove(ssn.getRemoteAddress().toString());
  136.     }

  137. }
client包,实现client功能 。连接服务端调用common接口提供的方法。
Client类,连接服务端,调用客户端的方法。
  1. package mina.client;

  2. import java.net.InetSocketAddress;

  3. import mina.common.Apple;

  4. import org.apache.mina.common.ConnectFuture;
  5. import org.apache.mina.common.IoConnectorConfig;
  6. import org.apache.mina.transport.socket.nio.SocketConnector;

  7. public class Client {
  8.     public static void main(String[] args) throws Exception {

  9.         // Create TCP/IP connector.
  10.         SocketConnector connector = new SocketConnector();

  11.         // Set connect timeout.
  12.         ((IoConnectorConfig) connector.getDefaultConfig())
  13.                 .setConnectTimeout(15);

  14.         ClientIoHandler handler = new ClientIoHandler();

  15.         // Start communication.
  16.         ConnectFuture cf = connector.connect(new InetSocketAddress("localhost",
  17.                 8080), handler);

  18.         // Wait for the connection attempt to be finished.
  19.         System.out.println("start to join");
  20.         cf.join();
  21.         cf.getSession();

  22.         System.out.println("test get value="
  23.                 + RpcClientImpl.getInstance().getStringValue("adsf"222,
  24.                         new Apple()));

  25.         System.out.println("test get int value="
  26.                 + RpcClientImpl.getInstance().getIntValue());

  27.         System.out.println("test call process start.");
  28.         RpcClientImpl.getInstance().printPrice();
  29.         System.out.println("test call process end.");
  30.     }
  31. }


AbstractClientImpl类,为client实现接口时使用的超类。
  1. package mina.client;

  2. import org.apache.mina.common.IoSession;

  3. public abstract class AbstractClientImpl {
  4.     
  5.     IoSession session = null;
  6.     ClientIoHandler handler = null;
  7.     public IoSession getSession() {
  8.         return session;
  9.     }

  10.     public void setSession(IoSession session) {
  11.         this.session = session;
  12.     }

  13.     public ClientIoHandler getHandler() {
  14.         return handler;
  15.     }

  16.     public void setHandler(ClientIoHandler handler) {
  17.         this.handler = handler;
  18.     }
  19. }
RpcClientImpl类,客户端实现common中接口的类,实际上是一种伪实现,在各个方法中组装调用的接品,方法,参数等信息,传到服务端由服务端的通信处理类处理信息,实现服务端调用并返回结果。
  1. package mina.client;

  2. import java.util.ArrayList;
  3. import java.util.Date;
  4. import java.util.List;
  5. import java.util.Properties;

  6. import mina.common.Apple;
  7. import mina.common.RpcInterface;

  8. import org.apache.mina.common.ByteBuffer;

  9. public class RpcClientImpl extends AbstractClientImpl implements RpcInterface {

  10.     private static String IFNAME = RpcInterface.class.getName();
  11.     
  12.     private static RpcClientImpl instance = null;
  13.     
  14.     public static RpcClientImpl getInstance(){
  15.         if(instance == null){
  16.             instance = new RpcClientImpl();
  17.         }
  18.         return instance;
  19.     }
  20.     
  21.     public String getStringValue(String arg0,int arg1,Apple arg2) {
  22.         if(session!=null){
  23.             Properties prop = new Properties();
  24.             prop.setProperty("interface",IFNAME);
  25.             prop.setProperty("method","getStringValue");
  26.             prop.put("argc","3");//参数个数.
  27.         
  28.             //生成参数类型链表
  29.             List typeList = new ArrayList();
  30.             typeList.add(String.class);
  31.             typeList.add(Integer.TYPE);
  32.             typeList.add(Apple.class);
  33.             
  34.             //生成参数对象链表
  35.             List argList = new ArrayList();
  36.             argList.add(arg0);
  37.             argList.add(arg1);
  38.             argList.add(arg2);
  39.             
  40.             prop.put("types",typeList);
  41.             prop.put("args",argList);
  42.             
  43.             ByteBuffer bb = ByteBuffer.allocate(16);
  44.             bb.setAutoExpand( true );
  45.             bb.putObject(prop);
  46.             bb.flip();
  47.             System.out.println("bbb==="+bb.toString());
  48.             session.write(bb);
  49.         }
  50.         
  51.         try {
  52.             System.out.println("handler="+handler);
  53.             System.out.println("lock="+handler.lock);
  54.             printStamp("1");
  55.             synchronized(handler.lock){
  56.                 printStamp("2");
  57.                 handler.lock.wait();
  58.                 printStamp("3");
  59.                 if(handler.resultObject!=null){
  60.                     return String.valueOf(handler.resultObject);
  61.                 }
  62.             }
  63.         } catch (InterruptedException e) {
  64.             e.printStackTrace();
  65.         }
  66.         
  67.         return null;
  68.     }

  69.     public int getIntValue() {
  70.         if(session!=null){
  71.             Properties prop = new Properties();
  72.             prop.setProperty("interface",IFNAME);
  73.             prop.setProperty("method","getIntValue");
  74.             prop.put("argc",Integer.MAX_VALUE);
  75.             //prop.put("object",new Object());
  76.             ByteBuffer bb = ByteBuffer.allocate(16);
  77.             bb.setAutoExpand( true );
  78.             bb.putObject(prop);
  79.             bb.flip();
  80.             System.out.println("bbb==="+bb.toString());
  81.             session.write(bb);
  82.         }
  83.         try {
  84.             System.out.println("handler="+handler);
  85.             System.out.println("lock="+handler.lock);
  86.             printStamp("1");
  87.             synchronized(handler.lock){
  88.                 printStamp("2");
  89.                 handler.lock.wait();
  90.                 printStamp("3");
  91.                 if(handler.resultObject!=null){
  92.                     return Integer.parseInt(String.valueOf(handler.resultObject));
  93.                 }
  94.             }
  95.         } catch (InterruptedException e) {
  96.             e.printStackTrace();
  97.         }
  98.         
  99.         return Integer.MIN_VALUE;
  100.     }

  101.     
  102.     public void printStamp(String str){
  103.         System.out.println((new Date().toString())+" "+str);
  104.     }

  105.     public void printPrice() {
  106.         if(session!=null){
  107.             Properties prop = new Properties();
  108.             prop.setProperty("interface",IFNAME);
  109.             prop.setProperty("method","printPrice");
  110.             prop.put("argc",Integer.MAX_VALUE);//参数个数
  111.             
  112.             ByteBuffer bb = ByteBuffer.allocate(16);
  113.             bb.setAutoExpand( true );
  114.             bb.putObject(prop);
  115.             bb.flip();
  116.             System.out.println("bbb==="+bb.toString());
  117.             session.write(bb);
  118.         }
  119.         
  120.         try {
  121.             System.out.println("handler="+handler);
  122.             System.out.println("lock="+handler.lock);
  123.             printStamp("1");
  124.             synchronized(handler.lock){
  125.                 printStamp("2");
  126.                 handler.lock.wait();
  127.                 printStamp("3");
  128.                 return;
  129.             }
  130.         } catch (InterruptedException e) {
  131.             e.printStackTrace();
  132.         }
  133.         return;
  134.     }
  135. }
ClientIoHandler类,处理服务端通信的类,用于和服务端建立通信,处理由服务端发送过来的消息。
  1. package mina.client;

  2. import java.io.InputStream;
  3. import java.io.OutputStream;
  4. import java.util.ArrayList;
  5. import java.util.Iterator;
  6. import java.util.List;
  7. import java.util.Properties;

  8. import org.apache.mina.common.ByteBuffer;
  9. import org.apache.mina.common.IdleStatus;
  10. import org.apache.mina.common.IoSession;
  11. import org.apache.mina.handler.StreamIoHandler;

  12. public class ClientIoHandler extends StreamIoHandler{

  13.     IoSession session = null;
  14.     
  15.     List implList = new ArrayList();
  16.     
  17.     Object resultObject;
  18.     Object lock = new Object();
  19.     
  20.     public ClientIoHandler(){
  21.         //init impls.
  22.         RpcClientImpl impl = RpcClientImpl.getInstance();
  23.         implList.add(impl);
  24.         //impl.setHandler(this);
  25.     }
  26.     
  27.     private void initImpls(){
  28.         Iterator it = implList.iterator();
  29.         while(it.hasNext())
  30.         {
  31.             Object obj = it.next();
  32.             if(obj instanceof AbstractClientImpl){
  33.                 AbstractClientImpl impl = (AbstractClientImpl)obj;
  34.                 impl.setSession(session);
  35.                 System.out.println("add this handler");
  36.                 impl.setHandler(this);
  37.             }
  38.         }
  39.     }
  40.     
  41.     //收到服务端消息后的处理,框架内部为异步。在应用中改为同步。
  42.     public void messageReceived(IoSession session, Object buf) {
  43.         System.out.println("receive message.");
  44.         
  45.         System.out.println(buf.toString());
  46.         try{
  47.             if(buf instanceof ByteBuffer){
  48.                 Properties prop = (Properties)(((ByteBuffer)buf).getObject());
  49.                 System.out.println("received prop="+prop);
  50.                 String mark = prop.getProperty("mark");
  51.                 //根据mark类型,选择不同处理。
  52.                 if(mark.equals("REPLYCALL")){
  53.                     Object obj = prop.get("Object");
  54.                     synchronized(lock){
  55.                         System.out.println("result="+obj);
  56.                         resultObject = obj;
  57.                         lock.notify();
  58.                     }
  59.                 }else if(mark.equals("BROADCAST")){
  60.                     Object obj = prop.get("Object");
  61.                     System.out.println("BROADCAST obj="+obj);
  62.                 }else if(mark.equals("NOTIFY")){
  63.                     Object obj = prop.get("Object");
  64.                     System.out.println("NOTIFY obj="+obj);
  65.                 }else{
  66.                     System.out.println("unknow mark.mark="+mark);
  67.                 }
  68.             }else{
  69.                 System.out.println("class type error.");
  70.             }
  71.         } catch (ClassNotFoundException e) {
  72.             e.printStackTrace();
  73.         }
  74.     }
  75.     
  76.     protected void processStreamIo(IoSession session, InputStream is, OutputStream os) {
  77.         System.out.println("process stream info,"+session.getRemoteAddress());
  78.     }

  79.     public void sessionOpened(IoSession session) {
  80.         // Set reader idle time to 10 seconds.
  81.         // sessionIdle(...) method will be invoked when no data is read
  82.         // for 10 seconds.
  83.        System.out.println("open session..");
  84.         this.session = session;
  85.        initImpls();
  86.        session.setIdleTime(IdleStatus.READER_IDLE, 10);
  87.     }

  88.     public void sessionClosed(IoSession session) {
  89.         // Print out total number of bytes read from the remote peer.
  90.         System.err.println("Total " + session.getReadBytes() + " byte(s)");
  91.     }

  92.     public void sessionIdle(IoSession session, IdleStatus status) {
  93.         // Close the connection if reader is idle.
  94.         if (status == IdleStatus.READER_IDLE)
  95.             session.close();
  96.     }
  97. }


需要改进的地方:
    在实际应用中,还需要精简客户端的结构,实现多个impl,一个handler,即实现一个将消息dispatch方法。服务端对客户端的主动消息还需要另外定义格式,以满足不同条件下的需要。或者需要定义内容比较详细的事件。
0 0