| 
				 该类并没有做过多处理,只是简单地调用了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类,记录用户的交互信息 
 * 包含:服务器为其分配的编号、该客户与服务器连接的句柄 
 *       和为该客户连接的商业对象 
*/ 			
				 |