[原譯]C#編寫FTP客戶端軟體
[原譯]C#編寫FTP客戶端軟體
1 介紹
我知道。網上有很多現成的FTP軟體。但是。我們也想要了解FTP的一些底層機構,因此。 這個開源的專案在你學習FTP知識的時候也許對你有些幫組。程式的介面看起來像FileZilla,FileZilla雖然流行但是有些bug,當我開啟我部落格的時候總是有問題。我需要通過FTP連線我的伺服器。傳送檔案,下載檔案等等。因為。我決定寫我自己的軟體來處理所有的情況。FileZilla足夠好。但它不是我的。
2 背景
看看我們已經知道的。我們知道FTP是一個標準的基於TCP網路協議。用於從一個主機向另一個主機傳輸檔案。它是一個C/S架構。
圖2
FTP程式曾經是基於命令列的。我們仍沿可以通過cmd.exe連線FTP伺服器。因為FTP的確可以通過命令來操作。舉個例子。我們可以在命令列使用“stor”命令來發送檔案。為了完成這些請求。FTP伺服器需要一直執行等待即將到來的客戶端請求。我們可以從來自維基百科的解釋更好的理解FTP:
客戶端計算機可以通過伺服器的21埠和伺服器通訊。叫做控制連線。它在一次會話期間保持開放。第一次連線的時候。叫做資料連線,伺服器可以對客戶端開啟20埠(主動模式),建立一條資料通路,連線上客戶端傳輸資料。或者客戶端開啟一個隨機的埠(被動模式),去連線伺服器,來傳輸資料。控制連線使用一個類似Telnet的協議,被用作客戶端和伺服器會話管理(命令,標識,密碼)。。比如。"RETRfilename" 會從伺服器端下載檔案。
圖三
一個完整的FTP檔案傳輸需要建立兩種型別的連線,一種為檔案傳輸下命令,稱為控制連線,另一種實現真正的檔案傳輸,稱為資料連線。
伺服器 通過三位ASCII的數字狀態碼,可能包含可選的描述資訊,在控制連線上做出迴應。比如。“200”或者是“200 OK”,表示上一條命令成功了。數字代表編號,描述資訊給出了一些說明(比如“OK”),或者可能是一些需要的引數(比如需要帳號來儲存檔案),那麼我們需要怎麼做呢。很明顯。傳送命令,接收“OK”迴應,傳送資料。接收資料。完了。但是首先需要伺服器已經準備好了。FTP伺服器可以在主動和被動兩種模式下執行。主動模式是基於伺服器的連線而被動模式是基友客戶端的連線。繼續看。
在主動連線中,客戶端把自己的ip和埠傳送給伺服器。然後伺服器嘗試連線到客戶端,但是可能會因為防火牆的原因而被拒絕。我們在windows上都會使用反病毒/自帶防火牆。是吧。那麼我們來看看被動模式
在被動連線中。伺服器通過一個“PASV”命令把自己的ip和埠傳送給客戶端。然後客戶端通過該IP嘗試連線伺服器。對於傳送檔案非常有用。當我們傳送檔案的時候。優先使用“PASV”模式,如你們所說。大多數協議。像FTP/HTTP 使用ASCII編碼,因為全球可用。因此我們會使用這種編碼。你可以從下面得到FTP的命令列表
主動和被動都是對於伺服器端來說的
3 使用程式碼
現在我們已經為編寫軟體做好準備了。我們寫些有用的程式碼吧。:)首先。我們“開啟檔案對話方塊”,整合到我們的窗體裡。
3.1 資源管理器元件
我們需要一個資源管理器元件在軟體介面可以看到我們所有的檔案。這樣我們才可以選擇哪些檔案來發送到FTP伺服器,新建一個Windows窗體控制元件庫(下載包中提供了)
圖四
最後看起來樣子是上面這樣。先新增一個TreeView,一些按鈕,和一個搜尋功能
TreeView.Nodes.Clear(); TreeNode nodeD = new TreeNode(); nodeD.Tag = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); nodeD.Text = "Desktop"; nodeD.ImageIndex = 10; nodeD.SelectedImageIndex = 10; TreeView.Nodes.Add(nodeD);
就像上面程式碼展示的那樣。我們需要新增地一個主節點。我的文件。我的電腦等等。然後獲得子目錄。
string[] dirList; dirList = Directory.GetDirectories(parentNode.Tag.ToString()); Array.Sort(dirList); if (dirList.Length == parentNode.Nodes.Count) return; for (int i = 0; i < dirList.Length; i++) { node = new TreeNode(); node.Tag = dirList[i]; node.Text = dirList[i].Substring(dirList[i].LastIndexOf(@"\") + 1); node.ImageIndex = 1; parentNode.Nodes.Add(node); }
可以從下載包裡看到完整的程式碼。我們還應該處理滑鼠單擊事件。
現在我們有了一個資源管理器。還有FTP和VS所需要的所有資訊。
首先,我們連線伺服器。我們應該怎麼做呢?
FTPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); AppendText(rchLog,"Status : Resolving IP Address\n",Color.Red); remoteAddress = Dns.GetHostEntry(Server).AddressList[0]; AppendText(rchLog, "Status : IP Address Found ->" + remoteAddress.ToString() + "\n", Color.Red); addrEndPoint = new IPEndPoint(remoteAddress, Port); AppendText(rchLog,"Status : EndPoint Found ->" + addrEndPoint.ToString() + "\n", Color.Red); FTPSocket.Connect(addrEndPoint);
是的。我們需要一個socket連線到伺服器 ,然後傳送命令
AppendText(rchLog, "Command : " + msg + "\n", Color.Blue); Byte[] CommandBytes = Encoding.ASCII.GetBytes((msg + "\r\n").ToCharArray()); FTPSocket.Send(CommandBytes, CommandBytes.Length, 0); //read Response ReadResponse();
我們傳送命令到伺服器。伺服器以他自己的語言來響應。我們需要理解他。響應包括3位數字和一些解釋。
private string SplitResponse() { try { while (true) { Bytes = FTPSocket.Receive(Buffer, Buffer.Length, 0); //Number Of Bytes (Count) StatusMessage += Encoding.ASCII.GetString(Buffer, 0, Bytes); //Convert to String if (Bytes < Buffer.Length) //End Of Response break; } string[] msg = StatusMessage.Split('\n'); if (StatusMessage.Length > 2) StatusMessage = msg[msg.Length - 2]; //Remove Last \n else StatusMessage = msg[0]; if (!StatusMessage.Substring(3, 1).Equals(" ")) return SplitResponse(); for (int i = 0; i < msg.Length - 1; i++) AppendText(rchLog, "Response : " + msg[i] + "\n", Color.Green); return StatusMessage; } catch(Exception ex) { AppendText(rchLog, "Status : ERROR. " +ex.Message+ "\n", Color.Red); FTPSocket.Close(); return ""; } }
完了。現在我們可以下載,上傳,重新命名。或者刪除了。
4 FTP命令列表
命令 | 描述 |
ABOR | 中斷一個活動的檔案傳輸 |
ACCT | 系統帳號資訊 |
ADAT | 認證/安全資料 |
ALLO | 分配空間來接收檔案 |
APPE | 新增檔案到伺服器 |
AUTH | 認證/安全機制 |
CCC | 清除命令通道 |
CDUP | 轉到父目錄 |
CONF | 機密性保護命令 |
CWD | 改變伺服器上的工作目錄 |
DELE | 刪除伺服器上的指定檔案 |
ENC | 機密保護通道 |
EPRT | 指定一個伺服器應該連線的擴充套件地址和埠 |
EPSV | 進入擴充套件的被動模式 |
FEAT | 得到伺服器提供的功能列表 |
HELP | 返回指定命令資訊 |
LANG | 返回語言資訊 |
LIST | 如果是檔名列出檔案資訊,如果是目錄則列出檔案列表 |
LPRT | 指定一個伺服器應該連線的長地址和埠 |
LPSV | 進入長被動模式 |
MDTM | 返回檔案最近修改時間 |
MIC | 完整的保護命令 |
MKD | 建立目錄 |
MLSD | 列出指定目錄的內容 |
MLST | 在命令列上列出物件的精確資訊 |
MODE | 傳輸模式(S=流模式,B=塊模式,C=壓縮模式) |
NLST | 列出指定目錄內容 |
NOOP | 無動作,(虛包,來自常連線中) |
OPTS | 選擇一個功能的選項 |
PASS | 驗證密碼 |
PASV | 進入被動模式 |
PBSZ | 保護緩衝區大小 |
PORT | 指定伺服器應該連線的地址和埠 |
PROT | 資料通道保護級別 |
PWD | 顯示當前工作目錄 |
QUIT | 從FTP伺服器上退出登入 |
REIN | 重新初始化登入狀態連線 |
REST | 由指定點重啟檔案傳遞 |
RETR | 傳遞檔案副本 |
RMD | 在伺服器上刪除指定目錄 |
RNFR | 從舊名稱重新命名 |
RNTO | 到新名稱 |
SITE | 向遠端伺服器傳送指定命令 |
SIZE | 返回檔案大小 |
SMNT | 掛載指定檔案結構 |
STAT | 返回當前狀態 |
STOR | 儲存(複製)檔案到伺服器上 |
STOU | 儲存檔案到伺服器指定檔案上 |
STRU | 設定結構(F=檔案,R=記錄,P=頁面) |
SYST | 返回伺服器使用的作業系統 |
TYPE | 傳輸模式(A=ASCII,E=EBCDIC,I=binary) |
USER | 驗證使用者 |
XCUP | 跳到當前工作路徑的父目錄 |
XMKD | 新建目錄 |
XPWD | 輸出當前工作目錄 |
XRMD | 刪除目錄 |
5 返回碼列表
- 2xx –返回成功
- 4xx or 5xx – 返回失敗
- 1xx or 3xx – 錯誤或不完整的回覆
第二位定義了錯誤的型別
- x0z – 語法 – 有語法錯誤.
- x1z – 資訊 – 請求提供資訊
- x2z – 連線 – 說明控制或資料連線有問題
- x3z – 賬戶認證 – 登入或者是賬戶認證有問題.
- x4z – 未定義
- x5z – 檔案系統 – 可能是伺服器檔案系統有問題。
Demo 下載
6 許可
本文包括原始碼和檔案在CPOL下授權。