1. 程式人生 > >《網際網路程式設計(Java)》——課程筆記5:網路檔案傳送程式設計

《網際網路程式設計(Java)》——課程筆記5:網路檔案傳送程式設計

學會基本的檔案傳輸FTP程式設計技術。

前兩講我們學會了使用TCP套接字(Socket),能實現字串的傳送和接收功能,簡單地做到了客戶機和伺服器的對話。

今天,我們進一步學習TCP套接字,利用它的位元組傳輸技術,實現網路檔案傳輸。

檔案傳輸協議規定(RFC 959 FTP.txt),網路檔案傳輸中用兩個TCP埠來實現:

一個埠(21號)用來對話,傳遞控制資訊,總是開啟;

一個埠(20號)實現檔案資料傳遞服務,有資料傳輸服務時開啟。

                                           FTP的兩個埠

用2021埠實現對話服務,如身份驗證、檔案目錄資訊瀏覽等,用2020埠傳遞資料檔案(即檔案上傳下載)。

程式設計知識點:位元組流(網路位元組流和檔案位元組流)的讀寫技術,進一步參考檔案,詳見文章“Java套接字程式技術比較研究.doc”

   基於C/S軟體架構的主要程式模組如下:

   客戶端程式有:

  主介面客戶端程式FileClientJFrame.java;

  檔案對話客戶端程式(控制程序)FileDialogClient.java;

  檔案資料客戶端程式(資料傳輸程序)FileDataClient.java。

 服務端程式:

 檔案對話伺服器程式FileDialogServer.java,開啟2021埠;

  主要功能:身份驗證、檔案目錄傳送。

 檔案資料伺服器程式FileDataServer.java,開啟2020埠。

主要功能:根據請求的檔名傳送檔案,接收檔案。

一、程式設計第一步:建立遠端檔案對話程式

        客戶端程式主要功能:傳送使用者資訊,瀏覽檔案目錄,實現和檔案伺服器的基本對話。

1. 新建一個程式包:ftpClient,用於存放遠端檔案操作相關的程式。

2. 將TCPClient.java程式重構、複製、並命名為FileDialogClient.java,原有的方法保持不變。

(1)   重構、複製TCPClientThreadJFrame、並命名為FileClientJFrame,新增“下載”和“上傳”2個按鈕;

(2)   執行程式FileClientJFrame,效果是否如圖2;

(3)   申明FileDialogClient物件,並定義2個全域性變數:ip, port;

(4)   在介面的“連線”按鈕中例項化FileDialogClient物件,並定義和啟動“讀”執行緒;

(5)   在介面的“傳送”按鈕中呼叫FileDialogClient.java的傳送方法;

(6)   在介面的“退出”按鈕中呼叫FileDialogClient.java的關閉方法。

(7)   //執行視窗程式,輸入一個公用的FTP伺服器的地址,或教學用的FTP伺服器:192.168.2*1.*4:2021,連線成功後傳送一些基本FTP命令,觀察返回結果;

(8)   新增快捷功能:

在使用者介面設計狀態,滑鼠右擊資訊顯示區,選擇“事件”、“MouseMotion”、“mousedragged”,鍵入如下程式碼:

jTextField1.setText(jTextArea1.getSelectedText());//滑鼠加亮的字串會自動出現在資訊錄入行中。

二、 程式設計第二步:

建立客戶端資料傳送程序FileDataClient.java

    主要功能:連線伺服器資料埠、傳送檔名、儲存下載的檔案或上傳檔案,檔案傳輸完成後關閉資料連線。

該程式有3個方法:

(1)構造方法,FileDataClient(String ip,String port),主要功能是向伺服器的資料埠請求連線;

(2)檔案下載方法fileGet(fileName)

    主要功能是準備當地磁碟空檔案,向伺服器傳送檔名(基於字串輸出流操作),然後接收網路檔案資料並儲存當地磁碟(基於位元組流操作),關閉資料套接字。

     在介面的“下載”按鈕中呼叫該方法,如:

         String fName=jTextField1.getText();

         jTextField1.setText("");

         new FileDataClient(ip,port).fileGet(fName);

部分具體程式碼:

    private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {                                         
         String fName=jTextField1.getText();
         jTextField1.setText("");
        try {
            String ip="202.*16.1*5.22";
            String port="2021";
            new FileDataClient(ip,port).fileGet(fName);
            // TODO add your handling code here:
        } catch (IOException ex) {
            Logger.getLogger(FileClientJFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }          

檔案下載部分:

   public String fileGet(String fName) throws IOException{
      boolean flag=false;
        //Object dataSocket = null;
 
     if(dataSocket!=null){//自定義變數dataSocket
       byte[] buff=new byte[1024*2];//用來緩衝接收的位元組資料
         
        //(1)檔案儲存對話方塊.
  
        JFileChooser chooser=new JFileChooser();
        File saveFile=new File(fName);
        chooser.setSelectedFile(saveFile);
        int stat=chooser.showSaveDialog(null);
        if(stat==JFileChooser.APPROVE_OPTION)
         saveFile=chooser.getSelectedFile();
       else
         saveFile=null;
      
        if(saveFile!=null){
           FileOutputStream fileOut=new FileOutputStream(saveFile); //新建本地空檔案.
 
       InputStream socketIn= dataSocket.getInputStream();//網路位元組輸入流
       OutputStream socketOut=dataSocket.getOutputStream();//網路位元組數出流
 
       //(2)傳送請求的檔名,字串讀寫功能 
       PrintWriter pw=new PrintWriter(new OutputStreamWriter(socketOut,"GB2312"),true);
       pw.println(fName);
 
        //(3)接收伺服器的資料檔案,位元組讀寫功能
           int len=socketIn.read(buff);//讀一塊到緩衝區.
             while(len!=-1){
                fileOut.write(buff,0,len);//寫一塊到檔案.
                len=socketIn.read(buff);
                flag=true;
             }
     //(4)檔案傳輸完畢,關閉資料套接字。
         fileOut.close();
         //JOptionPane.showMessageDialog(null, "檔案接收完畢.");
          dataSocket.close();
          if(flag)
                return "檔案下載成功.";
            else{
                saveFile.delete();
                return "檔名錯誤或檔案下載失敗.";
               }
           }else{
                 dataSocket.close();
            return "本地檔案建立失敗.";
           }
       }else
        return "伺服器連線失敗.";
}
}