你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 网络与通信
4.6 C/S模式中的远程方法调用(中)
 

该类并没有做过多处理,只是简单地调用了Exception父类的构造方法。代码如下:

import java.io.*;

/**

 *自定义异常类

*/

public class TunnelException extends Exception{

   public TunnelException(String message){

      super(message);

   }

}

第六步:编写商业对象代理类BusObjectProxy.java,实际也是网络数据流的解调制类(客户端)。

该类的构造函数就是初始化:包括接收客户端的用户名、密码登录信息,然后与服务器建立连接,并向服务器发送9999报头和用户名、密码,请求服务器通过验证。其他的方法就是实现接口BusInterface中定义的所有业务逻辑。当然这个实现只是象征性的。实现的代码如下:

import java.io.*;

import java.util.Vector;

/**

 *

 *服务器主类的客户端代理

  */

public class BusObjectProxy extends TunnelClient implements BusInterface{

   /**

    *调用TunnelClient的初始化函数,建立连接,并向服务器发送9999报头

    *提供客户端用户名和密码进行登录请求。

    */

   public BusObjectProxy(String name,String pass)

 throws TunnelException,IOException{

      setUserName(name);

      setUserPass(pass);

      initialize();

   }

   /**

    *实现接口中定义的方法

    *代理负责将入口参数打包发送到服务器

    *并返回从服务器获得的结果

    *方法1-- 功能:获取指定目录的所有文件名和目录名

    *           编号:1

    *           入口参数:路径名,例如"d:\\s"

    *           返回值:对象FileAndDirectory

    */

   public FileAndDirectory getAllFileName(String path){

      FileAndDirectory fd=null;

      try{

         writeHeader(1);

         //向字节流中写入入口参数

         writeObject(new String(path));

         //读报头

         readHeader();

         //从输入流中获取执行的结果

         fd=(FileAndDirectory)readObject();

      }

      catch(Exception ex){

         ex.printStackTrace();

         fd=null;

      }

      return fd;

   }

}

第七步:编写服务器端负责调制类的网络层封装部分TunnelServer.java(服务器)。

负责服务器端口监听的创建,信息在网络上的分发、接收、服务端界面创建、客户连接SESSION管理等,这段代码比较复杂,使用的Java程序设计技巧也多,比如抽象类定义、内隐类定义等。实现的代码如下:

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import java.net.*;

import java.io.*;

import java.util.*;

/**

 *服务器端负责处理网络数据报的调制类

 *

 *参考类: Talk   ClientSession

  */

public abstract class TunnelServer extends JFrame implements Runnable{

    private static ServerSocket serverSocket;  //服务器端监听socket

    private static Socket clientSocket;   //与客户连接的句柄

    private static ClientSession cs;       //客户的SESSION

    private static Hashtable ht=new Hashtable();  //存放所有客户连接(“连接顺号-客户SESSION”)

    private DataInputStream in;

    private DataOutputStream out;

    private int port=7484;

    int count=0;  //连接总数

    public static JTextArea ta=new JTextArea(12,34);

    JButton btn=new JButton("启动");

    public void startServer(int port) throws Exception{

       try{

          //建立服务器监听Socket

          serverSocket=new ServerSocket(port);

          ta.append("Server Listener Created at port "+port+"......\n");

       }catch(IOException ex){}

       //启动客户连接侦听器

       Thread thread=new Thread(this);

        thread.start();

    }

    public void run(){

        try{

          //每隔500毫秒检测一次

          Thread.sleep(500);

          //实现客户端循环监听

          while(true){

             //获取到一个客户连接

             clientSocket=serverSocket.accept();

             //指定数据流封装方式

             in=new DataInputStream(clientSocket.getInputStream());

             out=new DataOutputStream(clientSocket.getOutputStream());

             //将该客户连接保存到哈希表中

             //  主要有:商业业务逻辑对象,与客户相关的Socket,编号

             synchronized (ht){

                    count++;

                    Object serverBusObject=getRealObject();

                    cs=new ClientSession(count,clientSocket,serverBusObject);

                    ht.put(Integer.toString(count),cs);

             }

             ta.append("Connection from "+

 clientSocket.getInetAddress().getHostAddress()+"\n");

             String lineSep=System.getProperty("line.separator");  //取得回车换行符

             InetAddress addr=serverSocket.getInetAddress().getLocalHost();

             String outData="编号为"+count+

"的访问者:欢迎您登陆EAC服务器。  服务器地址:"+

addr+

" 当前服务的端口号为:"+serverSocket.getLocalPort();

             //根据收发协议的规定,首先进行身份验证

             //初始化的第一个报头一定是9999,所以没有保存该报头的信息。

             int flag=readHeader();

              ta.append("::> request header:"+flag+"\n");

             //从客户端获取用户名和密码

             String userName=(String)readObject();       

             String userPass=(String)readObject();

             ta.append("::> received from client"+count+"  name="+userName);

             ta.append(" and password="+userPass+"\n");         

             //系统初始化,接收到9999报头,模拟系统身份验证

             if(correctLogin(userName,userPass)){

                  ta.append("::> access is legal,client "+count+

",you are welcome!"+"\n");

                  writeHeader(9999);

                  writeObject(outData);

                  //管理每一个客户的完整交互过程,

//注意:客户的每个完整交互过程是在一个新线程中完成的。

                  new Talk(count,ht,ta){

                      public void executeMethod(Object busObject,

int flag,DataInputStream in,DataOutputStream out)

throws Exception{

                           executeMethods(busObject,flag,in,out);

                      }

                 }.start();

             }

             else{

                  ta.append("::> guest logging in declined\n");

                  writeHeader(-1);

                  out.writeUTF("你无权登录网络,请联系系统管理员");

             }

          }

        }catch(Exception ex){}

    }

/**

*  将对象写入字节流,先写入一个整型数,表示对象的长度,然后再写对象本身

    *  调用该函数前应该先创建DataOutputStream对象out

    */

   public void  writeObject(Object obj) throws Exception{

      try{

        //首先将对象转为字节流

        ByteArrayOutputStream buf=new ByteArrayOutputStream();

        ObjectOutputStream oos=new ObjectOutputStream(buf);

        oos.writeObject(obj);

        byte[] bytes=buf.toByteArray();

        int l=bytes.length;

        //写入对象长度

        out.writeInt(l);

        //写入对象字节流        

        out.write(buf.toByteArray());

        out.flush();

      }

      catch(Exception ex){

        ex.printStackTrace();

      }

   }

   /**

* 从输入流中读取一个对象,先读出该对象占用字节数,然后读对象本身

* 调用该函数前应该存在DataInputStream对象in

*/

   public Object readObject() throws Exception{

      try{

          //读入对象的长度

          int  l=in.readInt();

          //构造对象字节流数组

          byte[] bytes=new byte[l];

          in.readFully(bytes);

          //返回对象本身

          ByteArrayInputStream buf=new ByteArrayInputStream(bytes);         

          ObjectInputStream ois=new ObjectInputStream(buf);

          return ois.readObject();

      }

      catch(Exception ex){

          ex.printStackTrace();

          return null;

      }

   }

   //向输出流写入报头

   public void writeHeader(int flag) throws TunnelException{

      try{

         out.writeInt(flag);

         out.flush();

      }catch(IOException ex){

         ex.printStackTrace();

         throw new TunnelException(ex.getMessage());

      }

   }

   //读取报头

   public int readHeader() throws TunnelException{

      int f=-1;

      try{

         //获取从服务器返回的信息

         //先读报头信息

         f=in.readInt();

      }catch(IOException ex){

         f=-1;

         ex.printStackTrace();

         throw new TunnelException(ex.getMessage());

      }

      return f;

   }

   //模拟系统登录过程,在这里可以使用数据库

   private boolean correctLogin(String name,String pass){

      if(name.equals("qixiaorui") && pass.equals("20000203")){

         return true;

      }

      else{

         return false;

      }

   }

   public int getPort(){

       return port;

   }

   public void setPort(int port){

       this.port=port;

   }

   /**

*获取商业对象实例

*/

   public abstract Object getRealObject() throws TunnelException;

   /**

* 执行flag指定的远程方法,详细内容在收发协议里有规定

*/

   public abstract void executeMethods(Object busObject,

int flag,DataInputStream in,DataOutputStream out)

throws Exception;

}

/**

 *用户交互监听处理类

 *负责处理用户的完整交互过程

 */

abstract class Talk extends Thread implements Runnable{

   private int count;

   private Hashtable ht;

   private JTextArea ta;

   public Talk(int count,Hashtable ht,JTextArea ta){

        this.count=count;

        this.ht=ht;

        this.ta=ta;

   }

   public void run(){

         try{

                while(true){

                     sleep(1000);

                     String response="";

                     Socket clientSock=

((ClientSession)ht.get(Integer.toString(count))).getClientSock()

                     Object serverBusObject=

((ClientSession)ht.get(Integer.toString(count))).getBusObject();

                     DataInputStream in=

new DataInputStream(clientSock.getInputStream());

                     DataOutputStream out=

new DataOutputStream(clientSock.getOutputStream());

                     //读取报头

                     int flag=in.readInt();

                     ta.append("client "+count+

":> execute remote method header="+flag+"\n");

                     //执行报头协议里定义的本地方法

                     executeMethod(serverBusObject,flag,in,out);  

                 }

         }catch(Exception ex){}

   }

   public abstract void executeMethod(Object busObject,int flag,

DataInputStream in,DataOutputStream out) throws Exception;

}

/**

 * 用户SESSION类,记录用户的交互信息

 * 包含:服务器为其分配的编号、该客户与服务器连接的句柄

 *       和为该客户连接的商业对象

*/

  推荐精品文章

·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 
·2023年7月目录
·2023年6月目录 
·2023年5月目录
·2023年4月目录 
·2023年3月目录 
·2023年2月目录 
·2023年1月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089