1. 程式人生 > >用java實現ftp的多執行緒下載

用java實現ftp的多執行緒下載

1:位元組流結構:
每次傳送12+1024個位元組
其中,前七個位元組位元組表示命令
第七到第十二個位元組表示後面1024位元組中的有效位元組的長度
例如一幀中前12個位元組的內容為"UPFILEN00012"表示要上傳檔名,檔名的長度是12。那麼程式就在後面的1024個位元組中去12個位元組,在把它轉換為字串,作為要上傳的檔名。

2:命令結構
Server端:
DISCONN:斷開連線
LSFILES:傳送當前目錄檔案列表
ENDFILE:上傳一個檔案的結束標記
UPFILEN:表示要上傳一個新的檔案,並且此包中包含了檔名
UPDATAS:表示本包是要上傳的資料
DNFILEN:表示要下載的檔名,伺服器要執行向客戶端傳輸檔案的操作
Client端:
DISCONN:斷開連線
LSFILES:接收伺服器當前目錄檔案列表
ENDFILE:下載一個檔案的結束標記
DNDATAS:表示本包是要下載的資料

3:檔案結構
FtpServer:ftp軟體的伺服器端,目前在埠2121監聽,支援多執行緒,檔案的上傳,下載,列表。
FtpClient:ftp軟體的客戶端,預設連線本機的伺服器端,在埠2121,支援檔案的上傳,下載,列表。
FtpClientUI:ftp軟體的客戶端的使用者介面,完全採用Swing技術,手工編寫,沒有用JB自動生成。
PublicFunc:提供一些公共的靜態方法例如將給定的String物件分裝成要傳送的幀。將數字格式化成長度為五位的String型別物件。
package cn.edu.bit.software.ftptrans;

import java.io.*;
import java.net.*;
import java.util.Vector;
import java.util.logging.*;

public class FtpServer
{
  //客戶端socket物件
  private ServerSocket m_servSocket;

  //ftp伺服器的埠號
  private int SERVER_PORT;

  //ftp伺服器所允許的最大連線數
  private int MAX_CONN;

  //連入的客戶端處理物件管理器
  private Vector vecClient;

  //設定一個log日誌物件
  private Logger mylog;

  private ConsoleHandler handler;

  String strServHome;

  public FtpServer(int servPort, int maxConn)
  {
    SERVER_PORT = servPort;
    MAX_CONN = maxConn;
    strServHome = "c://";
    vecClient = new Vector();
    /*------------初始化log------------*/
    try
    {
      handler = new ConsoleHandler();
      handler.setLevel(Level.ALL);
      mylog = Logger.getLogger("FtpServer");
      mylog.addHandler(handler);
      mylog.setLevel(Level.ALL);
    }
    catch (SecurityException e)
    {
      mylog.warning("在設定程式日誌級別時出現異常");
      mylog.warning(e.getMessage());
    }

    /*--------------初始化伺服器,埠2121----------------------*/
    try
    {
      m_servSocket = new ServerSocket(SERVER_PORT, MAX_CONN);
      while (true)
      {
        mylog.finest("FtpServer開始在埠2121監聽");
        Socket clientSocket = m_servSocket.accept();
        vecClient.add(clientSocket);
        mylog.info("#" + vecClient.size() + "號客戶端連入");
        new TransHandler(this, clientSocket, vecClient.size()).start();
      }
    }
    catch (IOException e)
    {
      mylog.warning("在初始化FtpServ時出現錯誤");
      mylog.warning(e.getMessage());
    }
  }

  public void deleteClient(TransHandler handler)
  {
    try
    {
      vecClient.remove(handler);
      vecClient.setSize(vecClient.size() - 1);
      mylog.info("第#" + handler.iClientNum + "號客戶端斷開了與伺服器的連線!");
    }
    catch (Exception e)
    {
      mylog.warning("在刪除第#" + handler.iClientNum + "號客戶端時出現異常");
      mylog.warning(e.getMessage());
    }
  }

  public static void main(String[] args)
  {
    new FtpServer(2121, 50);
  }
}

/**
 * 當有客戶端連入時,處理客戶端請求的類
 * @author findfrog
 * @version 1.0
 */
class TransHandler extends Thread
{
  //伺服器控制代碼,用於最後銷燬TransHandler物件時用
  FtpServer main = null;
  //客戶端的socket
  private Socket m_clientSocket = null;

  //日誌物件
  private Logger mylog;

  //要上傳的檔案路徑
  private String strUpFilePath = null;

  //要下載的檔案路徑
  private String strDnFilePath = null;

  //本客戶端在的序號
  int iClientNum = -1;

  //緩衝位元組資料的大小
  private int ibufferlength;

  //緩衝位元組陣列
  byte[] inputBytes;

  //從客戶端傳來的指令
  String strClientOrder;
  //用於得到從socket端的輸入資訊
  InputStream m_inputStream;
  //用於向socket輸出的輸出流
  OutputStream m_outputStream;
  //用於上傳檔案的輸出流
  FileOutputStream m_fileOutputStream;
  //用於下載檔案的輸入流
  FileInputStream m_fileInputStream;

  //建構函式
  public TransHandler(FtpServer fserver, Socket s, int iNum)
  {
    try
    {
      main = fserver;
      //將客戶端socket控制代碼付給本地物件
      m_clientSocket = s;
      //初始化log物件
      mylog = Logger.getLogger("TransHandler");
      //初始化本客戶端序號
      iClientNum = iNum;
      //用於得到從socket端的輸入資訊
      m_inputStream = m_clientSocket.getInputStream();
      m_outputStream = m_clientSocket.getOutputStream();
      ibufferlength = 1024;
      inputBytes = new byte[ibufferlength + 12];

    }
    catch (Exception e)
    {
      mylog.warning("在初始化TransHandler時發生異常!");
      mylog.warning(e.getMessage());
    }
  }

  public void run()
  {
    try
    {
      int ilength;
      while ( (ilength = m_inputStream.read(inputBytes, 0, 12 + ibufferlength)) !=
             -1)
      {
        strClientOrder = new String(inputBytes, 0, 7);
        if (strClientOrder.equals("DISCONN"))
        { //斷開連線
          mylog.info("得到了DISCONN");
          exit();
        }
        else if (strClientOrder.equals("LSFILES"))
        { //傳送當前目錄檔案列表
          mylog.info("伺服器端接收到了LSFILES命令");
          File flHome = new File(main.strServHome);
          String[] strFileNames = flHome.list();
          strFileNames = AdjustStrings(strFileNames);
          for (int i = 0; i < strFileNames.length; i++)
          {
            String strFileNameLength = PublicFunc.formatLength(strFileNames[i].
                getBytes().length);
            byte[] fileNameBytes = strFileNames[i].getBytes();
            byte[] outBytes = PublicFunc.makepackage("LSFILES",
                strFileNameLength, fileNameBytes);
            m_outputStream.write(outBytes, 0, outBytes.length);
            m_outputStream.flush();
          }
        }
        else if (strClientOrder.equals("ENDFILE"))
        { //上傳一個檔案的結束標記
          mylog.info("收到檔案結束標誌符號");
          m_fileOutputStream.close();
        }
        else if (strClientOrder.equals("UPFILEN"))
        { //表示要上傳一個新的檔案,並且此包中包含了檔名
          int iFileNameLength = Integer.parseInt(new String(inputBytes, 7, 5));
          mylog.info("要上傳的檔名的長度為" + iFileNameLength);
          String strFileName = new String(inputBytes, 12, iFileNameLength);
          mylog.info("要上傳的檔名是:" + strFileName);
          //初始化上傳檔案路徑
          strUpFilePath = main.strServHome + strFileName;
          File upFile = new File(strUpFilePath);
          m_fileOutputStream = new FileOutputStream(upFile);
        }
        else if (strClientOrder.equals("UPDATAS"))
        { //表示本包是要上傳的資料
          //本次資料包的長度
          mylog.info("正在接收檔案...");
          int iDataLength = Integer.parseInt(new String(inputBytes, 7, 5));
          m_fileOutputStream.write(inputBytes, 12, iDataLength);
          m_fileOutputStream.flush();
        }
        else if (strClientOrder.equals("DNFILEN"))
        { //表示要下載的檔名,伺服器要執行向客戶端傳輸檔案的操作
          int iFileNameLength = Integer.parseInt(new String(inputBytes, 7, 5));
          mylog.info("要下載的檔名的長度為" + iFileNameLength);
          String strFileName = new String(inputBytes, 12, iFileNameLength);
          mylog.info("要下載的檔名是:" + strFileName);
          //初始化上傳檔案路徑
          strDnFilePath = main.strServHome + strFileName;
          File dnFile = new File(strDnFilePath);
          //初始化了檔案輸出流
          m_fileInputStream = new FileInputStream(dnFile);

          //開始向客戶端傳輸檔案
          mylog.info("開始向客戶端傳輸檔案" + strFileName + "...");
          int iInputLength = 0;
          String strInputLength;
          byte[] readBytes = new byte[ibufferlength];
          while ( (iInputLength = m_fileInputStream.read(readBytes, 0,
              ibufferlength)) !=
                 -1)
          {
            strInputLength = PublicFunc.formatLength(iInputLength);
            byte[] outBytes = PublicFunc.makepackage("DNDATAS", strInputLength,
                readBytes);
            m_outputStream.write(outBytes, 0, outBytes.length);
            m_outputStream.flush();
          }

          //最後傳送一個檔案結束標記
          m_outputStream.write(PublicFunc.makepackage("ENDFILE", "00001",
              new byte[1]));
          m_outputStream.flush();
        }
      }
    }
    catch (Exception e)
    {
      mylog.warning(e.getMessage());
    }
  }

  public void exit()
  {
    try
    {
      m_outputStream.write(PublicFunc.makepackage("DISCONN", "00001",
                                                  new byte[1]));
      m_inputStream.close();
      m_outputStream.close();
      main.deleteClient(this);
      main = null;
    }
    catch (Exception e)
    {
      mylog.warning("在斷開客戶端#" + this.iClientNum + "連線時出現異常!");
      mylog.warning(e.getMessage());
    }
  }

  public String[] AdjustStrings(String[] strFileNames)
  {
    String[] strItemNames = new String[strFileNames.length + 1];
    strItemNames[0] = "返回上一級";
    int j = 1;
    for (int i = 0; i < strFileNames.length; i++)
    {
      File upFile = new File(main.strServHome + strFileNames[i]);
      if (!upFile.isFile())
      {
        strItemNames[j++] = "[資料夾]" + strFileNames[i];
      }
    }
    for (int i = 0; i < strFileNames.length; i++)
    {
      File upFile = new File(main.strServHome + strFileNames[i]);
      if (upFile.isFile())
      {
        strItemNames[j++] = strFileNames[i];
      }
    }

    return strItemNames;
  }

}

package cn.edu.bit.software.ftptrans;

import java.io.*;
import java.net.*;
import java.util.logging.*;
import java.util.Vector;

public class FtpClient extends Thread
{
  Logger mylog = Logger.getLogger("FtpClient");
  Socket m_clientSocket;
  //緩衝位元組資料的大小
  private int ibufferlength;

  //緩衝位元組陣列
  byte[] inputBytes;

  Vector vecServFiles;

  //用於得到從socket端的輸入資訊
  InputStream m_inputStream;
  //用於向socket輸出的輸出流
  OutputStream m_outputStream;
  //向本地寫檔案的檔案輸出流
  FileOutputStream m_fileOutputStream;
  //從本地讀檔案的檔案輸入流
  FileInputStream m_fileInputStream;
  //從伺服器端傳來的指令
  String strServerOrder;
  //主機的ip地址
  String strServerIP;
  //伺服器的埠號
  int iServerPort;

  public FtpClient(String strServIP, int iServPort)
  {
    strServerIP = strServIP;
    iServerPort = iServPort;
  }

  public void run()
  {
    try
    {
      //建立連線
      m_clientSocket = new Socket(strServerIP, iServerPort);
      mylog.info("已經連到了主機" + strServerIP + "在埠" + iServerPort);
      m_inputStream = m_clientSocket.getInputStream();
      m_outputStream = m_clientSocket.getOutputStream();
      mylog.fine("客戶端得到了socket的輸入輸出流!");
      ibufferlength = 1024;
      inputBytes = new byte[ibufferlength + 12];
      vecServFiles = new Vector();
      doBusiness();
    }
    catch (UnknownHostException e)
    {
      mylog.warning("伺服器地址未知");
      mylog.warning(e.getMessage());
    }
    catch (IOException e)
    {
      mylog.warning(e.getMessage());
    }
    catch (Exception e)
    {
      mylog.warning(e.getMessage());
    }
  }

  public void doBusiness()
  {
    try
    {
      int iLength = 0;
      while ( (iLength = m_inputStream.read(inputBytes, 0, ibufferlength + 12)) !=
             -1)
      {
        strServerOrder = new String(inputBytes, 0, 7);
        if (strServerOrder.equals("DISCONN"))
        { //斷開連線
          mylog.info("在client端得到了DISCONN");
          int length = Integer.parseInt(new String(inputBytes, 7, 5));
          mylog.info("長度是" + length);
        }
        else if (strServerOrder.equals("LSFILES"))
        { //接收伺服器當前目錄檔案列表

          int iDataLength = Integer.parseInt(new String(inputBytes, 7, 5));
          mylog.info("在客戶端這個檔名的長度是:" + iDataLength);
          String strFileName = new String(inputBytes, 12, iDataLength);
          mylog.info("客戶端正在獲取伺服器目錄資訊....." + strFileName);
          vecServFiles.add(strFileName);
        }
        else if (strServerOrder.equals("ENDFILE"))
        { //下載一個檔案的結束標記
          mylog.info("收到下載檔案結束標誌符號");
          m_fileOutputStream.close();
        }
        else if (strServerOrder.equals("DNDATAS"))
        { //表示本包是要下載的資料
          int iDataLength = Integer.parseInt(new String(inputBytes, 7, 5));
          m_fileOutputStream.write(inputBytes, 12, iDataLength);
          m_fileOutputStream.flush();
        }
      }
    }
    catch (Exception e)
    {

    }
  }

  /**
   * 客戶端上傳檔名
   * @param strFileName 要上傳檔案的檔名
   */
  public void upFileName(String strFileName)
  {
    try
    {
      String strLength = PublicFunc.formatLength(strFileName.getBytes().length);
      byte[] outBytes = PublicFunc.makepackage("UPFILEN", strLength,
                                               strFileName.getBytes());
      m_outputStream.write(outBytes, 0, outBytes.length);
      m_outputStream.flush();
    }
    catch (Exception e)
    {
      mylog.warning("在客戶端在向伺服器寫要上傳的檔名時發生異常");
      mylog.warning(e.getMessage());
    }
  }

  /**
   * 講本地檔案strFilePath上傳到伺服器
   * @param strFilePath 本地檔案路徑
   */
  public void upFileData(String strFilePath)
  {
    try
    {
      File file = new File(strFilePath);
      m_fileInputStream = new FileInputStream(file);

      int iInputLength = 0;
      String strInputLength;
      byte[] readBytes = new byte[ibufferlength];
      while ( (iInputLength = m_fileInputStream.read(readBytes, 0,
          ibufferlength)) !=
             -1)
      {
        strInputLength = PublicFunc.formatLength(iInputLength);
        byte[] outBytes = PublicFunc.makepackage("UPDATAS", strInputLength,
                                                 readBytes);
        m_outputStream.write(outBytes, 0, outBytes.length);
        m_outputStream.flush();
      }
      //最後傳送一個檔案結束標記
      m_outputStream.write(PublicFunc.makepackage("ENDFILE", "00001",
                                                  new byte[1]));
      m_outputStream.flush();
    }
    catch (Exception e)
    {
      mylog.warning("從客戶端向伺服器傳輸檔案內容是發生異常");
      mylog.warning(e.getMessage());
    }
  }

相關推薦

java實現FTP執行斷點續傳,上傳下載

package com.ftp;  import java.io.File;    import java.io.FileOutputStream;    import java.io.IOException;    import java.io.InputStream;    import java.io

java實現ftp執行下載

1:位元組流結構:每次傳送12+1024個位元組其中,前七個位元組位元組表示命令第七到第十二個位元組表示後面1024位元組中的有效位元組的長度例如一幀中前12個位元組的內容為"UPFILEN00012"表示要上傳檔名,檔名的長度是12。那麼程式就在後面的1024個位元組中去1

Java執行下載原理與實現

多執行緒下載原理 客戶端要下載一個檔案, 首先請求伺服器,伺服器將這個檔案傳送給客戶端,客戶端儲存到本地, 完成了一個下載的過程. 多執行緒下載的思想是客戶端開啟多個執行緒同時下載,每個執行緒只負責下載檔案的一部分, 當所有執行緒下載完成的時候,檔案下載完畢.

java使用 網路連線+RandomAccessFile + io 執行實現執行下載檔案並顯示實時網速

下載檔案的時候,一個大檔案切成很多片,用多執行緒下載,速度會快很多 閱讀程式碼的時候注意檢視程式碼裡面的註釋 想用多執行緒下載檔案,則, 第一:得了解  RandomAccessFile  類,這是個隨機訪問檔案類,裡面可以設定 訪問的 開始地址和結束地址,且該類可讀可

Java執行下載技術實現

多執行緒下載 多執行緒下載技術,簡單的說就是把要下載的檔案分成幾塊,由不同的執行緒來負責每一塊資料的下載任務。 技術要點 RandomAccessFile: Java中用來實現隨機訪問檔案的類 http Range請求頭 具體思路 1、檔案分塊。 檔案分塊大小(blockSize)= (

android 利用java中的執行和io流,最快速度的下載伺服器檔案,android 實現apk下載展現通知欄

首先,我們得來說下多執行緒下載實現的大致思路,以及在使用多執行緒下載過程應該需要注意的問題。      多執行緒下載實現的大致思路:      大致思路是這樣的,也就是把整個一個檔案資源分為若干個部分,然後開啟若干個執行緒,並且使得每個執行緒負責下載每個子部分的檔案,由於

Java實現FTP批量大檔案上傳下載(五) --執行效果圖

八、執行效果   1.上傳 (1).啟動上傳上面 (2).上傳中 (3).上傳中 (4).上傳成功 2.下載 (1)下載檔案的儲存路徑 (2)下載中 (3)下載中 (4)下載成功 九、小結 在本文中,筆者將在實際專案中的上傳下載

Java中使用執行結合斷點續傳實現一個簡單的檔案下載

這篇部落格介紹在android中使用多執行緒和斷點續傳實現一個簡單的檔案下載器 第一步:啟動Tomcat伺服器,將需要下載的檔案部署到Tomcat伺服器上 第二步:使用eclipse建立一個Java工程,並且在工程中新增下面的程式碼 package com.fyt.mul

libcurl實現執行下載

       libcurl官網(http://curl.haxx.se/)是一個很強大網路功能的庫,支援當前DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS,

Java筆記】執行實現簡單的非同步運算

實現Callable介面,重寫call()方法,使操作執行緒池時能帶有返回值的效果: import java.util.concurrent.Callable; public class GetSumCallable implements Callable<Integer> {

Java編寫的一個執行下載

這裡只是演示這個下載器如何使用以及介面 1.可以百度TIM:找到下載介面,複製下載地址: 2.貼上到下載器介面如下圖:(注意儲存地址一定是存在的) 3.點選開始下載:(如果想要暫停或者繼續可以先選中下載行,點選暫停或者繼續)

Java基礎之執行之原理、實現方式及匿名內部類建立執行方法

一、概念 程序:作業系統當中正在執行的一個程式。例如正在執行一個QQ。 執行緒:程序之內多工的執行單位。例如迅雷當中正在下載的多個電影。 JVM當中:棧(Stack)記憶體是執行緒獨立的,堆(Heap)記憶體是執行緒共享的。 (1)Java程式執行的時候至少有兩個執行緒: 1)主

Android實現執行下載檔案,支援斷點

本篇部落格主要介紹多執行緒去下載檔案,以下載多個app為例。不管去下在app,音視訊等檔案,實現起來都一樣。篇幅有點長,先貼張美女圖看看 正在下載的效果圖 下載完成效果圖 小編的下載路徑是放在sd卡的絕對路徑中,方便驗證! 工程目錄圖 介紹下每

Java執行下載網路檔案

新建一個JavaGUI介面 package Download; import java.awt.EventQueue; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.Action

java中的執行 內部類實現執行 Runable介面的實現

  /* java.lang.Thead      java中的多執行緒    類從  Thread  覆蓋run方法    呼叫start啟動x執行緒  java中如果執行緒只剩後臺執行緒那麼程式終止執行 setDaemon設定為後臺執行緒     當進城中只剩下後臺

Android 實現執行下載檔案+斷點續傳

                            Android 多執行緒下載檔案+斷點續傳       在專案快要結束的時候,發現了app沒有版本更新的功能,於是找到一些過去的資料,在app上應用完成了版本更新,現在記錄一下apk的下載,也就是如何通過多執行緒將ap

java執行下載檔案和斷點下載

多執行緒,斷點下載檔案 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOExcept

java基礎--24.執行的應用--電影院賣票程式的實現

A.多執行緒應用–電影院賣票程式的實現 A:繼承Thread類 B:實現Runnable介面 電影院賣票程式出問題 為了更符合真實的場景,加入了休眠100毫秒。 多執行緒賣票過程中可能出現的問題: a:同一張票多次出售

Android實現執行下載並顯示通知

1、前言 相信大家都使用過一些可以下載檔案的 App,在下載列表中通常都會顯示一個進度條實時地更新下載進度,現在的下載都是斷點重傳的,也就是在暫停後,重新下載會依照之前進度接著下載。 我們這個下載的案例是有多個執行緒同時下載一個任務,並能提供多個檔案同時下載

c#實現SQL池(執行),定時批量執行SQL語句 (轉)

在實際專案開發中,業務邏輯層的處理速度往往很快,特別是在開發Socket通訊服務的時候,網路傳輸很快,但是一旦加上資料庫操作,效能一落千丈,資料庫操作的效率往往成為一個系統整體效能的瓶頸。面對這問題,我們怎麼辦呢?好,下面我就為大家介紹一種方法:構建SQL池,分離業務邏輯層