这是一个课后练习。主要是熟练掌握IO流,还有TCP程序的一般开发步骤。


TCP程序开发的一般步骤:


Server端:


1.         创建ServerSocket ss在这里要指定监听端口。


2.         获得Socket s 通过ss.accept()方法获得客户端的连接请求。


3.         获得IO流 通过s.getInputStream和s.getOutputStream两个方法获得输入输出流


4.         处理数据,传送数据。


5.         关闭IO流


6.         关闭Socket s


7.         关闭ServerSocket ss


Client端:


1.         创建Socket s  在这里指定网络主机及其相应端口。


2.         获得IO流


3.         处理数据,传送数据


4.         关闭IO流


5.         关闭Socket s


本程序的基本功能是连接到服务器,在提交一个文件路径后,服务器判断是否是文本文件,是并且存在的话就传送文件内容到客户端。


为了功能更加人性化点,在客户端界面加入主机及其端口和文件地址文本框,还有连接,断开连接,下载文件按钮,下载的文件内容显示在文本域中,另外加一条状态栏,用于显示当前客户端状态。在服务器端界面加入监听端口文本框和开始监听按钮,日志信息显示在文本域中。


本程序基本功能实现,但容错性还不是很好。异常没进行处理。


本程序源码如下(开发语言JAVA,开发环境JDK 1.5 Windows 2003):


开发过程中遇到一个难点就是不知道如何判断网络流的结束,文件流中的readLine==null和read==-1都判断不出来,使客户端在等着读但服务器端已经结束。最后通过在服务器端传送完文件后,加传一个标志字符串(quit)用于通知客户端本次数据已经传送完毕。在客户端通过判断接收到的字符串是不是标志字符来结束读循环。但是这样又想到一个问题,那就是服务器端如果不是自己开发的,那怎么样实现两者间的通信呢?现在课程太紧了,暂时没时间处理。



字节流实现:


package  server;
 import  java.awt. * ;
 import  java.awt.event. * ;
 import  javax.swing. * ;
 import  java.net. * ;
 import  java.io. * ;
 import  java.util. * ;
 class  DownServer  extends  WindowAdapter  implements  ActionListener
 {
    JFrame jframe=new JFrame("远程文件查看器服务端");
    JPanel jpanel=new JPanel();
    JButton startJButton=new JButton("启动");
    JLabel label=new JLabel("监听端口");
    JTextField portJTextField=new JTextField(6);
    JTextArea logJTextArea=new JTextArea();
    JScrollPane logJScrollPane=new JScrollPane(logJTextArea);
    Date d=new Date();
    
    ServerSocket ss;
    Socket s;
    
    InputStream is;
    OutputStream os;
    BufferedInputStream bis;
    BufferedOutputStream bos=null;
    BufferedReader br;
    PrintWriter pw;
    byte[] b=new byte[1024];
    int len;
    StringBuffer sb;
    String filename;
    String port="6666";
    
    public DownServer()
    {
        jpanel.add(label);
        jpanel.add(portJTextField);
        jpanel.add(startJButton);
        startJButton.addActionListener(this);
        jframe.getContentPane().add(jpanel,"North");
        jframe.getContentPane().add(logJScrollPane);
        
        jframe.addWindowListener(this);
        jframe.setSize(400,300);
        jframe.setResizable(true);
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jframe.setVisible(true);
        
    }
    public void actionPerformed(ActionEvent e)
    {
        String str=e.getActionCommand();
        if(str.equals("启动"))
        {
            port=portJTextField.getText();
            logJTextArea.append(d.toString()+": 在 "+port+" 端口启动服务 ");
            Server s=new Server();
            s.start();
        }
        if(str.equals("停止"))
        {
            
        }
    }
    class Server extends Thread
    {
        public void run()
        {
            try{ss=new ServerSocket(Integer.parseInt(port));}catch(Exception e){e.printStackTrace();}            
            while(true)
            {
                try
                {                                
                    s=ss.accept();
                    is=s.getInputStream();
                    os=s.getOutputStream();            
                    bos=new BufferedOutputStream(os);
                    br=new BufferedReader(new InputStreamReader(is));
                    logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+" 请求连接成功! ");
                }
                catch(Exception e){e.printStackTrace();}
        
                sb=new StringBuffer();
                while(true)
                {    
        
                    try{filename=br.readLine();}catch(Exception e){e.printStackTrace();}
                    
                    if(filename.equals("quit"))
                    {                        
                        logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+"与服务器断开连接 ");
                        try
                        {
                            bos.close();
                            s.close();        
                        }
                        catch(Exception e){e.printStackTrace();}
                        finally
                        {
                            break;
                        }
                    }
                    logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+" 请求查看文件 "+filename+" ");
                    File f=new File(filename);
                    if(f.exists())
                    {
                        if(filename.endsWith(".java")||filename.endsWith(".txt")||filename.endsWith(".html")||filename.endsWith(".jsp")||filename.endsWith(".asp")||filename.endsWith(".css")||filename.endsWith(".xml"))
                            {                
                                try
                                {                        
                                    FileInputStream fis=new FileInputStream(f);
                                    BufferedInputStream bis=new BufferedInputStream(fis);
                                    byte[] b=new byte[1024];
                                    int len=0;
                                    StringBuffer sb=new StringBuffer();
                                    while((len=bis.read(b))!=-1)
                                    {    
                                        bos.write(b,0,len);
                                        bos.flush();                    
                                    }                       
                                    bis.close();               
                                    
                                    bos.write("quit".getBytes());
                                    bos.flush();
//                                    bos.close();                
                                }catch(Exception ex){}
                                logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+"文件传送成功 ");                    
                            }
                            else
                            {
                                try
                                {
                                    bos.write("此文件不是文本文件!".getBytes());
                                    bos.flush();
                                    bos.write("quit".getBytes());
                                    bos.flush();
                                }catch(Exception e){e.printStackTrace();}

                                logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+"非文本文件,没有传送 ");                                
                            }
                    }
                    else
                    {
                        try
                        {
                            bos.write("文件不存在".getBytes());
                            bos.flush();
                            bos.write("quit".getBytes());
                            bos.flush();    
                        }catch(Exception e){e.printStackTrace();}
                    
                        logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+"文件不存在,没有传送 ");                        
                    }
//                    bos.close();//输出流关闭后Socket也会关闭?//但不关那边又读不完?
                }
        //        bos.close();
        //        s.close();
        //        ss.close();                            
            }
        }    
    }
    public void windowClosing(WindowEvent e)
    {            
        try
        {
            bos.close();//如何知道一个流是否有被关闭了????
            if(s.isConnected())s.close();//s和ss还没有被创建呀.
            if(!ss.isClosed())ss.close();    
        }
        catch(Exception ex){ex.printStackTrace();}
        System.exit(0);
    }
    public static void main(String[] args) throws IOException
    {
        new DownServer();
    }
}
 

 package  client;

 import  java.awt. * ;
 import  java.awt.event. * ;
 import  java.io. * ;
 import  javax.swing. * ;
 import  java.net. * ;
 class  DownLoad  implements  ActionListener
 {
    JFrame frame=new JFrame("文本文件下载器");
    JTextField statu=new JTextField("断开连接");
    JTextField tfipaddress=new JTextField(16);
    JTextField tfport=new JTextField(5);
    JTextField tffilepath=new JTextField(30);
    JLabel lbaddress=new JLabel("服务器地址:");
    JLabel lbport=new JLabel("端口:");
    JLabel lbfilepath=new JLabel("文件地址");
    JButton btconnect=new JButton("连接");
    JButton btdisconnect=new JButton("断开连接");
    JButton btdownload=new JButton("下载");
    JTextArea tadownresult=new JTextArea(20,50);
    JScrollPane spdownresult=new JScrollPane(tadownresult);
    //JStatuBar
    JPanel  northpanel=new JPanel();
    JPanel  centerpanel=new JPanel();
    JPanel  northpanel1=new JPanel();
    JPanel  northpanel2=new JPanel();
    
    String address="127.0.0.1";
    String port="6666";
    
    Socket s;
    
    InputStream is;
    OutputStream os;
    BufferedInputStream bis;
    BufferedOutputStream bos;
    BufferedReader br;
    PrintWriter pw;
    
    
    byte[] b=new byte[1024];
    int len;
    
    StringBuffer sb=new StringBuffer();
    
    public DownLoad()
    {
        init();
        addListener();
        showFrame();        
    }
    
    public void init()
    {
        frame.add(northpanel,"North");
        frame.add(centerpanel);
        frame.add(statu,"South");
        statu.enable(false);
        btdisconnect.setEnabled(false);
        btdownload.setEnabled(false);
        
        northpanel.setLayout(new BorderLayout());
        northpanel.add(northpanel1,"North");
        northpanel.add(northpanel2);
        
        northpanel1.setLayout(new FlowLayout(FlowLayout.LEFT));
        northpanel1.add(lbaddress);
        northpanel1.add(tfipaddress);
        northpanel1.add(lbport);
        northpanel1.add(tfport);
        northpanel1.add(btconnect);
        northpanel1.add(btdisconnect);
        
        northpanel2.setLayout(new FlowLayout(FlowLayout.LEFT));
        northpanel2.add(lbfilepath);
        northpanel2.add(tffilepath);
        northpanel2.add(btdownload);
        
        centerpanel.setLayout(new BorderLayout());
        centerpanel.add(spdownresult);        
    }
    
    public void showFrame()
    {
        frame.pack();
//        frame.setSize(800,600);
        frame.setResizable(true);
        frame.setLocation(100,50);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    
    public void addListener()
    {
        btconnect.addActionListener(this);
        btdisconnect.addActionListener(this);
        btdownload.addActionListener(this);
    }
    
    public void actionPerformed(ActionEvent e)
    {
        String action=e.getActionCommand();
        if(action.equals("连接"))
        {
            if(!tfipaddress.getText().equals(""))address=tfipaddress.getText();
            if(!tfport.getText().equals(""))port=tfport.getText();
            try{s=new Socket(address,Integer.parseInt(port));receiveStream();}catch(Exception ex){ex.printStackTrace();}//如何设置一个Socket的连接超时?有ServerSocket设置.            
            if(s.isConnected())
            {
                statu.setText("已经连接");
                btconnect.setEnabled(false);
                btdisconnect.setEnabled(true);
                btdownload.setEnabled(true);
            }
            else
            {
                statu.setText("连接超时");
            }
        }
        if(action.equals("断开连接"))
        {
            try
            {
                pw.println("quit");
                pw.flush();
                pw.close();
                s.close();
                
            }catch(Exception ee){}
            statu.setText("断开连接");
            btconnect.setEnabled(true);
            btdisconnect.setEnabled(false);
            btdownload.setEnabled(false);            
        }
        if(action.equals("下载"))
        {
            tadownresult.setText("");
            String filename=tffilepath.getText();
            try
            {
                pw.println(filename);
                pw.flush();                
                
                while(true)
                {
                    len=bis.read(b);
                    String str=new String(b,0,len);
                    if(str.equals("quit"))break;
                    tadownresult.append(str+" ");
//                    String s=new String(b,0,len);                
//                    sb.append(s);                    
                }
//                String st=sb.toString();
//                System.out.println (st);
//                tadownresult.setText(st);                
            }
            catch(IOException eo){}            
        }
    }
    
    public void receiveStream()
    {
        try
        {
            is=s.getInputStream();
            os=s.getOutputStream();
                    
            bis=new BufferedInputStream(is);
            pw=new PrintWriter(os);
        }
        catch(IOException ex){}
    }
    
    public static void main(String[] args)
    {
        new DownLoad();
    }
}



字符流实现:


package  server;
 import  java.net. * ;
 import  java.io. * ;
 import  java.awt. * ;
 import  java.awt.event. * ;
 import  javax.swing. * ;
 import  java.util.Date;

 class  Server
 {
    JFrame frame=new JFrame("文件下载服务器端");
    JPanel panel=new JPanel();    
    JTextArea textarea=new JTextArea();
    JScrollPane scrollpane=new JScrollPane(textarea);
    JTextField port=new JTextField(5);
    JLabel label=new JLabel("监听端口:");
    JButton button=new JButton("启动");
    
    ServerSocket ss=null;
    Date d=new Date();
    
    public Server()
    {
        init();
    }
    
    public void init()
    {
        frame.add(panel,"North");
        frame.add(scrollpane);
        panel.add(label);
        panel.add(port);
        panel.add(button);
        button.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                if(port.getText().equals(""))
                {
                    JOptionPane jop=new JOptionPane();
                    jop.showMessageDialog(frame,"端口号不能为空");
                    return;
                }
                else
                {
                    try
                    {                        
                         ss=new ServerSocket(Integer.parseInt(port.getText()));                                                 
                         textarea.setText(d.toString()+" 在端口:"+port.getText()+" 启动文件下载服务 ");
                         DownServer ds=new DownServer();
                         ds.start();                         
                    }
                    catch(Exception io){io.printStackTrace();}                    
                }
            }
        });
        
        frame.setSize(800,600);
        frame.setResizable(false);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    
    public static void main(String[] args) throws IOException
    {
        new Server();
    }
    
    class DownServer extends Thread
    {        
        InputStream is;
        OutputStream os;
        BufferedInputStream bis;
        BufferedOutputStream bos;
        BufferedReader br;
        PrintWriter pw;
        byte[] b=new byte[1024];
        int len;
        StringBuffer sb;
        String filename;        
    
        
        public void run()
        {    
            String address=null;       
            while(true)
            {        
                try
                {
                    Socket s=ss.accept();
                    is=s.getInputStream();
                    os=s.getOutputStream();    
                    address=s.getInetAddress().toString();    
                    //字符流处理
                    br=new BufferedReader(new InputStreamReader(is));
                    pw=new PrintWriter(os);
                    textarea.append(address+" 在 "+d.toString()+" : 连接  ");
                }
                catch(Exception ex){ex.printStackTrace();}
                
        
                
        
                sb=new StringBuffer();
                while(true)
                {            
                    //字符流处理
                    try
                    {                        
                        filename=br.readLine();
                    }
                    catch(Exception ee){ee.printStackTrace();System.out.println ("异常!!!!!!!!");}            
                    
                    if(filename.equals("quit"))
                    {
                        textarea.append(address+" 在 "+d.toString()+" : 断开连接  ");
                        break;
                    }
                    File f=new File(filename);
                    textarea.append(address+"  "+d.toString()+" : 访问文件 "+filename+" ");
                    if(f.exists())
                    {
                        if(filename.endsWith(".java")||filename.endsWith(".txt")||filename.endsWith(".html")||filename.endsWith(".jsp")||filename.endsWith(".asp")||filename.endsWith(".css")||filename.endsWith(".xml"))
                            {                
                                try
                                {                         
                                    //字符流处理
                                    FileReader fr=new FileReader(f);
                                    BufferedReader br=new BufferedReader (fr); //使用ReadLine()一次读一行,怎么知道文件结束?
                                    String str=null;
                                    
                                    while((str=br.readLine())!=null)
                                    {                                        
                                        pw.println(str);
                                        pw.flush();
                                    }
                                    br.close();
                                    textarea.append(address+"  "+d.toString()+" : 访问文件 "+filename+" 成功 ");
                                    pw.println("quit");
                                    pw.flush();                                                          
                                }catch(Exception ex){}                    
                            }
                            else
                            {                           
                                //字符流处理
                                pw.println("此文件不是文本文件!");
                                pw.flush();
                                textarea.append(address+"  "+d.toString()+" 不是文本文件,下载失败 ");
                                pw.println("quit");  //(1)可以两边同时使用一个信息表示结束.(2)服务器端不做结束警告,客户端通过捕捉异常来结束.
                                pw.flush();
                            }
                    }
                    else
                    {          
                        //字符流处理
                        pw.println("文件不存在");
                        pw.flush();
                        textarea.append(address+"  "+d.toString()+" 文件不存在,下载失败 ");
                        pw.println("quit");
                        pw.flush();
                    }
    //                pw.close();//不关闭,客户端读不完,关闭,Socket也关了??????
                }
        //        pw.close();
        //        s.close();
        //        ss.close();
            }
        }
    }
}





package  client;

 import  java.awt. * ;
 import  java.awt.event. * ;
 import  java.io. * ;
 import  javax.swing. * ;
 import  java.net. * ;
 class  DownLoad  extends  WindowAdapter  implements  ActionListener
 {
    JFrame frame=new JFrame("文本文件下载器");
    JTextField statu=new JTextField("断开连接");
    JTextField tfipaddress=new JTextField(16);
    JTextField tfport=new JTextField(5);
    JTextField tffilepath=new JTextField(30);
    JLabel lbaddress=new JLabel("服务器地址:");
    JLabel lbport=new JLabel("端口:");
    JLabel lbfilepath=new JLabel("文件地址");
    JButton btconnect=new JButton("连接");
    JButton btdisconnect=new JButton("断开连接");
    JButton btdownload=new JButton("下载");
    JTextArea tadownresult=new JTextArea(20,50);
    JScrollPane spdownresult=new JScrollPane(tadownresult);
    //JStatuBar
    JPanel  northpanel=new JPanel();
    JPanel  centerpanel=new JPanel();
    JPanel  northpanel1=new JPanel();
    JPanel  northpanel2=new JPanel();
    
    Socket s;
    
    InputStream is;
    OutputStream os;
    BufferedInputStream bis;
    BufferedOutputStream bos;
    BufferedReader br;
    PrintWriter pw;
    
    
    byte[] b=new byte[1024];
    int len;
    
    StringBuffer sb=new StringBuffer();
    
    public DownLoad()
    {
        init();
        addListener();
        showFrame();        
    }
    
    public void init()
    {
        frame.add(northpanel,"North");
        frame.add(centerpanel);
        frame.add(statu,"South");
        statu.enable(false);
        btdisconnect.setEnabled(false);
        btdownload.setEnabled(false);
        
        northpanel.setLayout(new BorderLayout());
        northpanel.add(northpanel1,"North");
        northpanel.add(northpanel2);
        
        northpanel1.setLayout(new FlowLayout(FlowLayout.LEFT));
        northpanel1.add(lbaddress);
        northpanel1.add(tfipaddress);
        tfipaddress.setText("127.0.0.1");
        northpanel1.add(lbport);
        northpanel1.add(tfport);
        tfport.setText("6666");
        northpanel1.add(btconnect);
        northpanel1.add(btdisconnect);
        
        northpanel2.setLayout(new FlowLayout(FlowLayout.LEFT));
        northpanel2.add(lbfilepath);
        northpanel2.add(tffilepath);
        northpanel2.add(btdownload);
        
        centerpanel.setLayout(new BorderLayout());
        centerpanel.add(spdownresult);    
        
        frame.addWindowListener(this);    
    }
    
    public void showFrame()
    {
        frame.pack();
//        frame.setSize(800,600);
        frame.setResizable(true);
        frame.setLocation(100,50);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    
    public void addListener()
    {
        btconnect.addActionListener(this);
        btdisconnect.addActionListener(this);
        btdownload.addActionListener(this);
    }
    
    public void actionPerformed(ActionEvent e)
    {
        String action=e.getActionCommand();
        if(action.equals("连接"))
        {
            String address=tfipaddress.getText();
            String port=tfport.getText();
            if(address.equals("")||port.equals(""))
            {
                JOptionPane jop=new JOptionPane();
                jop.showMessageDialog(frame,"IP地址或端口号为空");
                return;
            }
            try
            {
                s=new Socket(address,Integer.parseInt(port));
                receiveStream();
            }catch(Exception ex)
            {
                statu.setText("连接失败");
                return;
            }//如何设置一个Socket的连接超时?有ServerSocket设置.            
        
            if(s.isConnected())
            {
                statu.setText("已经连接");
                btconnect.setEnabled(false);
                btdisconnect.setEnabled(true);
                btdownload.setEnabled(true);
            }
            else
            {
                statu.setText("连接超时");
            }
        }
        if(action.equals("断开连接"))
        {
            try
            {                
                pw.println("quit");
                pw.flush();
                pw.close();
                s.close();
            }catch(Exception ee){System.out.println ("发生异常");}
            statu.setText("断开连接");
            btconnect.setEnabled(true);
            btdisconnect.setEnabled(false);
            btdownload.setEnabled(false);                
        }
        if(action.equals("下载"))
        {
            String filename=tffilepath.getText();
            try
            {                
                //字符流处理
                pw.println(filename);
                pw.flush();
                tadownresult.setText("");
                sb=sb.delete(0,sb.length());
                String str=null;    
                while(true)
                {
                    str=br.readLine();
                    if(str.equals("quit"))break;             
                    sb.append(str+" ");
//                    tadownresult.append(str+" ");
                }  
                tadownresult.setText(sb.toString());            
            }
            catch(IOException eo){}            
        }
    }
    
    public void receiveStream()
    {
        try
        {
            is=s.getInputStream();
            os=s.getOutputStream();

            //字符流处理
            br=new BufferedReader(new InputStreamReader(is));
            pw=new PrintWriter(os);
        }
        catch(IOException ex){}
    }
    
    public static void main(String[] args)
    {
        new DownLoad();
    }
    
    public void windowClosing(WindowEvent we)
    {    
        if(s!=null)
        {
            if(s.isConnected())
            {        
                pw.println("quit");
                pw.flush();
                pw.close();
                try{s.close();}catch(IOException ioe){ioe.printStackTrace();}
            }
        }
        System.exit(0);
    }
}