日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

[C# 网络编程系列]专题十二:实现一个简单的FTP服务器

發布時間:2023/12/18 C# 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [C# 网络编程系列]专题十二:实现一个简单的FTP服务器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

引言:

休息一個國慶節后好久沒有更新文章了,主要是剛開始休息完心態還沒有調整過來的, 現在差不多進入狀態了, 所以繼續和大家分享下網絡編程的知識,在本專題中將和大家分享如何自己實現一個簡單的FTP服務器。在我們平時的上網過程中,一般都是使用FTP的客戶端來對商家提供的服務器進行訪問(上傳、下載文件),例如我們經常用到微軟的SkyDrive網盤,115網盤等,然而我們經常用到的都是網頁版本的,網頁版本和客戶端版本的不同,網頁版本的FTP客戶端,它與服務器的交流是使用HTTP協議發出對服務器的請求的,而客戶端版本采用的是FTP協議發出命令對服務器進行請求。然后我們接觸到FTP服務器卻很少的, 所以本專題中將和大家介紹下如何實現一個FTP服務器(不要覺得服務器很深奧一樣的,大家可以簡單的認為服務器也是一個程序,該程序是對客戶端發來的請求做處理的,請求大家可以簡單理解為字符串,從這個角度看, 服務器程序就是一個對字符串解析的過程。),也是為后面的一個專題做一個鋪墊,因為后面專題將和大家介紹下FTP客戶端——文件上傳下載器,有了自己自定義的FTP服務器后, 自定義的FTP客戶端就可以對自定義的FTP服務器進行訪問,使兩者形成一個完整的軟件,從而也讓大家對基于FTP協議的工具有一個初步的了解。

?

一、基于FTP協議的客戶端和服務器是如何"溝通的"?

FTP客戶端和FTP服務器之間的“溝通”分為四個階段的:

1. 啟動FTP

客戶通過FTP客戶端軟件,發起FTP交互式的命令,就是告訴服務器(也就是一臺電腦,服務器上與一個程序(FTP服務)會接收命令,并解析發來的命令,然后發出回復信息)說:“我想和你聊聊天,可以嗎?”

2. 建立控制連接

客戶端TCP層根據客戶給出的服務器IP地址,向服務器提供FTP服務的21號端口發出主動建立連接的請求,服務器接收到請求后,通過3次握手之后,客戶端和服務器之間就建立一個TCP連接(就是一條通道,就好比生活中馬路,有了馬路之后車才能夠在兩地之間運送東西),之后,所有用戶發出的FTP命令和服務器的回應都是通過該連接來傳送的, 所以也把這個TCP連接叫做控制連接,控制連接在用戶退出之前一直存在。

3. 建立數據連接和進行文件傳輸

現在客戶端和服務器端已經建立聊天的通道了(控制連接),但是兩者聊天過程中如果互相想贈送禮物要怎么辦呢?(這里形象的把客戶端和服務器端文件的傳輸比喻兩個人通過聊天后互相贈送禮物的過程),此時我們就需要另外一條馬路(數據連接)來進行“禮物的贈送”了,具體贈送禮物的過程如下:

  • ?客戶端通過控制連接向服務器發送一個上傳文件的命令時,會自己分配一個臨時的TCP端口號。
  • ?客戶端通過控制連接向服務器發送一個命令(下面將會介紹的PORT命令)來告訴服務器自己的IP地址和臨時的端口號,然后再發送一條上傳文件的命令(可以理解為——客戶端要送禮物給服務器時,實際上不是簡單的發送一個送禮物命令的,在這之前還需要發送一條自我介紹命令(就是告訴服務器自己的IP地址和端口號)來告訴服務器自己就是剛剛和它聊天的那位,這也很符合我們日常送禮物的流程的,一般大家接到禮物都要弄明白送禮物的人是誰,是不是自己認識的)
  • 服務器接收到客戶端的IP地址和臨時端口號后,以這個IP地址和端口號為目標,使用服務器上的20端口(該端口是用來傳輸數據的端口)向客戶端發出主動建立連接的請求。
  • ?客戶端收到請求后,通過3此握手后就與服務器之間建立了另外一條TCP連接——數據連接,即用來互相送禮物的通道。
  • ?客戶端在自己的文件系統中選擇要贈送(上傳)的文件
  • ?客戶端將文件寫入到文件傳輸進程中(寫入網絡流中)
  • ?服務器端將傳輸來的文件在服務器端的文件系統中進行存儲
  • ?文件傳輸完成后,由服務器主動關閉該數據的連接
  • 4 關閉FTP

    當用戶退出FTP時,通關客戶端發送退出命令,之后控制連接被關閉,FTP服務結束。

    二、從上面的溝通過程中你明白了什么?

    從上面客戶端與服務器端的溝通過程中,這里可以概括幾點:

    (1)客戶端與服務器端進行交互過程中,傳輸層使用的是TCP協議而不是其他傳輸層協議

    (2)溝通過程有兩條TCP連接——一條是控制連接,即傳輸命令和響應信息的通道,另一條是數據連接,即傳輸文件的馬路,并且必須先有控制連接才能建立數據連接,因為要進行文件傳輸首先必須知道客戶的IP地址和端口號,這個過程就是通過控制連接傳送的命令來告知服務器客戶端的IP地址和端口號,之后再在兩者之間建立數據連接來傳輸文件

    (3)在服務器端,控制連接(端口號為21)和數據連接(端口號 為20)使用了不同的端口號

    三、贈送禮物的方式?——文件傳輸模式

    客戶端與FTP服務器建立數據連接之后,首先需要告訴服務器采用哪種文件傳輸模式,FTP提供了兩種文件傳輸模式,一種是主動(Port)模式,另一種是被動(Passive)模式。

    主動模式——服務器向客戶端發起數據連接請求,被動模式——客戶端向服務器發起數據請求。

    然而兩種模式有什么相同點和不同點呢?

    兩種模式的相同點: 服務器都使用21號端口進行用戶驗證和管理

    不同點: 傳送文件數據的方式不一樣,主動模式的FTP服務器數據端口固定在20,而被動模式的FTP服務器數據端口則在1025~65535之間的隨機數。

    3.1 主動模式

    主動模式——服務器主動連接客戶端,然后傳輸文件,在這種模式下,FTP客戶端先用一個端口N(N>1024)向服務器的21號端口發起控制連接,連接成功后,在發出PORT N+1命令告訴服務器自己監聽的端口為N+1;服務器接受到該命令后,用一個新的數據端口(20號端口)與客戶端的端口N+1建立連接,然后進行文件傳輸,而客戶端則通過監聽N+1端口接受文件數據。

    注意: 采用主動模式存在一個問題,如果客戶端安裝了防火墻或在內網時,由于防火墻一般不允許接受外部發起的標準端口以外的連接請求,因此外部FTP服務器就無法使用主動模式穿過防火墻主動連接客戶端(這里與客戶端連接的端口為N+1(N>1024),非標準端口),從而造成無法傳送文件數據,此時就需要采用被動模式傳送文件了。

    3.2 被動模式

    被動模式——服務器被動接受客戶端連接請求,即控制連接請求和數據連接請求都是由客戶端發起,在這種模式下,FTP客戶端先隨機開始一個端口N向服務器的21號端口發起控制連接,然后向服務器發送PASV命令。服務器收到該命令后,會用一個新的端口P(P>1024)進行監聽,同時將該端口號告訴客戶端,客戶端接受到響應命令后,再通過新的端口N+1連接服務器的端口P,然后進行文件數據傳輸。

    注意:采用被動模式與主動模式也存在相同的問題,如果服務器安裝了防火墻,客戶端同樣可能無法與服務器端的端口P建立數據請求,因為該請求可能會被防火墻過濾掉。在實際應用中,服務器一般指定一個端口范圍,允許客戶端與該范圍內的端口建立數據連接,而不再這個范圍內的端口會被服務器的防火墻過濾掉,從而在一定程度上消除了針對服務器的惡意攻擊。

    四、 FTP協議中有哪些命令的?

    協議簡單說就是一個規范,就好比打牌一樣,制定一個大家都能明白的規則,斗地主的規則被大家都認可的,但是私下我們也可以自定義規則來玩的(例如說三個只能帶一個等這樣的規則),同樣FTP規則也是大家都認可的一個協議,我們當然也可以自定義協議。

    由于.Net平臺下目前還沒有提供對FTP服務器端開發的類庫,因此要實現一個FTP服務器端的應用程序,就必須了解FTP協議的詳細內容。

    4.1 FTP命令有哪些?

    FTP 協議中規定了一些大家都認識的命令和組成。FTP協議中的命令都由3~4個字母組成,命令與參數之間用空格隔開,每個命令用回車換行結束。

    (1)訪問命令

    (1)訪問命令有:

    USER命令——格式為:USER <username>, 指定登錄的用戶名,以便服務器進行身份驗證。這個命令通常是控制連接后第一個發出的命令

    PASS命令——格式為:PASS <password>, 指定用戶密碼,該命令必須跟在登錄用戶名命令之后。

    REIN命令——格式為:REIN, 表示重新初始化用戶信息,該命令終止當前USER的傳輸,同時終止正在傳輸的數據,然后重置所有參數,并打開控制連接,以便客戶端再次發生USER命令。

    QUIT命令——格式為:QUIT,關閉與服務器的連接

    (2)模式設置命令:

    PASV命令——格式為:PASV,該命令告訴FTP服務器,讓FTP服務器在指定的數據端口進行監聽,被動接受客戶端的請求。如果未指定任何模式,FTP服務器默認使用PASV模式

    PORT命令——格式為:PORT <address>,該命令告訴FTP服務器,客戶端監聽的端口號是address,讓FTP服務器采用主動模式連接客戶端。

    TYPE命令——格式為: TYPE <data type>,該命令指定要傳輸的數據類型,有ASCII和BINARY兩種類型。

    MODE命令——格式為:MODE <mode>,該命令指定傳輸模式,S表示流,B表示塊,C表示壓縮。

    (3)文件管理命令

    CWD命令——格式為:CWD <directory>,該命令是用戶可以在不同的目錄或數據集下工作而不用改變登錄信息,directory一般是目錄名或與系統相關的文件集合。

    PWD命令——格式為:PWD,該命令返回當前工作目錄。

    MKD命令——格式為:MKD <directory>,該命令表示在指定路徑下創建新目錄,directory 表示特定目錄的字符串。

    CDUP命令——格式為:CDUP,該命令表示回到上層目錄

    RMD命令——格式為:RMD <directory>,刪除指定目錄,directory表示特定目錄的字符串。

    LIST命令——格式為:LIST <name>,該命令返回指定路徑下的子目錄及文件列表,name 為路徑。省略路徑時,返回當前路徑下的文件列表。

    NLIST命令——格式為:NLIST <directory>,該命令返回指定路徑下的目錄列表,省略路徑時,返回當前目錄。

    RNFR命令——格式為:RNFR <old path>,該命令表示重新命名文件,該命令的下一條命令用RNTO指定新的文件名。

    RNTO命令——格式為:RNTO <new path>,該命令和RNFR命令共同完成對文件的重命名。

    DELE命令——格式為:DELE <filename>,該命令表示刪除指定路徑下的文件

    (4)文件傳輸命令:

    RETR命令——RETR <filename>,表示下載指定路徑的文件

    STOR命令——STOR <filename>,表示上傳一個指定的文件,并將其存儲在指定的位置,如果文件已存在,原文件將被覆蓋,如果文件不存在,則創建新文件。

    (5)其他命令

    SYST命令——格式為:SYST,該命令返回服務器使用的操作系統。

    4.2 FTP響應碼

    客戶端發送FTP命令后,服務器需要返回FTP響應碼,響應碼即是回答,我們平常聊天中別人問了說了話或者問了問題,另外一方就需要回答,FTP協議中定義以響應碼的形式來作為回答,FTP響應碼由ASCII編碼的3位數字開頭,后面接一行文本提示信息,數字和提示信息中有一個空格,如XXX 接收請求。

    每個響應碼同樣以回車換行結束。

    FTP響應碼的3位數字每位都有特定的意義,具體見下表:

    響應碼

    表示

    1

    1XX

    表示信息已被服務器正確接收,但尚未被處理

    2XX

    表示信息已被服務器正確處理完畢

    3XX

    彪西信息已被服務器正在接受,并正在處理中

    4XX

    表示信息處理錯誤(暫時)

    5XX

    表示信息處理錯誤(永久)

    2

    X0X

    表示語法錯誤

    X1X

    表示系統狀態與信息

    X2X

    表示與FTP服務器系統連接狀態

    X3X

    表示與用戶認證有關的信息

    X4X

    表示未定義

    X5X

    表示與文件系統有關的信息

    ?下表列出了常用的響應碼所代表的意義:

    響應碼

    意義

    響應碼

    意義

    110

    重新啟動標記應答

    332

    登陸是需要賬戶信息

    120

    服務在指定時間內準備好

    350

    請求的文件操作需要進一步命令

    125

    數據連接打開——開始傳輸

    421

    服務關閉

    150

    文件狀態良好,將要打開數據連接

    425

    不能打開數據連接

    200

    命令成功

    426

    關閉連接,終止傳輸

    202

    命令沒有執行

    450

    文件不可用

    211

    系統狀態回復

    451

    中止請求操作:有本地錯誤

    212

    目錄狀態回復

    452

    磁盤空間不足

    213

    文件狀態回復

    500

    無效命令

    214

    幫助信息回復

    501

    語法錯誤

    215

    系統類型回復

    502

    命令未執行

    220

    服務就緒

    503

    命令順序錯誤

    221

    服務關閉控制連接,可以退出登陸

    504

    無效命令參數

    225

    數據連接打開,無傳輸正在進行

    530

    未登陸

    226

    關閉數據連接,請求的文件操作成功

    532

    存儲文件需要賬戶信息

    227

    進入被動模式

    550

    未執行請求操作

    230

    用戶已登陸

    551

    請求操作終止:頁類型未知

    250

    請求的文件操作完成

    552

    請求文件操作終止:超過存儲分配

    257

    創建路徑名

    553

    為執行請求的操作:文件名不合法

    331

    用戶名正確,需要口令

    ?

    ?

    五、實現自定義的FTP服務器

    相信大家看完上面的介紹對FTP協議以及FTP客戶端和FTP服務器的交互過程有一定的理解的,這時候大家知道理論后就一定很想知道知道這些之后可以做什么的?答案就是可以制作一個簡單的FTP服務器,大家可以根據代碼來進一步理解FTP協議。下面是程序中一些核心代碼片段:

    View Code // 啟動服務器private void btnFtpServerStartStop_Click(object sender, EventArgs e){if (myTcpListener == null){listenThread = new Thread(ListenClientConnect);listenThread.IsBackground = true;listenThread.Start();lstboxStatus.Enabled = true;lstboxStatus.Items.Clear();lstboxStatus.Items.Add("啟動Ftp服務...");btnFtpServerStartStop.Text = "停止";}else{myTcpListener.Stop();myTcpListener = null;listenThread.Abort();lstboxStatus.Items.Add("Ftp服務已停止!");lstboxStatus.TopIndex = lstboxStatus.Items.Count - 1;btnFtpServerStartStop.Text = "啟動";}}// 監聽端口,處理客戶端連接private void ListenClientConnect(){myTcpListener = new TcpListener(IPAddress.Parse(tbxFtpServerIp.Text), int.Parse(tbxFtpServerPort.Text));// 開始監聽傳入的請求 myTcpListener.Start();AddInfo("啟動成功!");AddInfo("Ftp服務運行中...[單機”停止“退出]");while (true){try{// 接收連接請求TcpClient tcpClient = myTcpListener.AcceptTcpClient();AddInfo(string.Format("客戶端({0})與本機({1})建立Ftp連接", tcpClient.Client.RemoteEndPoint, myTcpListener.LocalEndpoint));User user = new User();user.commandSession = new UserSeesion(tcpClient);user.workDir = tbxFtpRoot.Text;Thread t = new Thread(UserProcessing);t.IsBackground = true;t.Start(user);}catch{break;}}}// 處理客戶端用戶請求private void UserProcessing(object obj){User user = (User)obj;string sendString = "220 FTP Server v1.0";RepleyCommandToUser(user, sendString);while (true){string receiveString = null;try{// 讀取客戶端發來的請求信息receiveString = user.commandSession.streamReader.ReadLine();}catch(Exception ex){if (user.commandSession.tcpClient.Connected == false){AddInfo(string.Format("客戶端({0}斷開連接!)", user.commandSession.tcpClient.Client.RemoteEndPoint));}else{AddInfo("接收命令失敗!" + ex.Message);}break;}if (receiveString == null){AddInfo("接收字符串為null,結束線程!");break;}AddInfo(string.Format("來自{0}:[{1}]", user.commandSession.tcpClient.Client.RemoteEndPoint, receiveString));// 分解客戶端發來的控制信息中的命令和參數string command = receiveString;string param = string.Empty;int index = receiveString.IndexOf(' ');if (index != -1){command = receiveString.Substring(0, index).ToUpper();param = receiveString.Substring(command.Length).Trim();}// 處理不需登錄即可響應的命令(這里只處理QUIT)if (command == "QUIT"){// 關閉TCP連接并釋放與其關聯的所有資源 user.commandSession.Close();return;}else{switch (user.loginOK){// 等待用戶輸入用戶名:case 0:CommandUser(user, command, param);break;// 等待用戶輸入密碼case 1:CommandPassword(user, command, param);break;// 用戶名和密碼驗證正確后登陸case 2:switch (command){case "CWD":CommandCWD(user, param);break;case "PWD":CommandPWD(user);break;case "PASV":CommandPASV(user);break;case "PORT":CommandPORT(user, param);break;case "LIST":CommandLIST(user, param);break;case "NLIST":CommandLIST(user, param);break;// 處理下載文件命令case "RETR":CommandRETR(user, param);break;// 處理上傳文件命令case "STOR":CommandSTOR(user, param);break;// 處理刪除命令case "DELE":CommandDELE(user, param);break;// 使用Type命令在ASCII和二進制模式進行變換case "TYPE":CommandTYPE(user, param);break;default:sendString = "502 command is not implemented.";RepleyCommandToUser(user, sendString);break;}break;} }} }

    ?

    程序演示截圖:

    ?首先在F:\盤下新建文件夾MyFtpServerRoot,在其中創建目錄結構并放一些文件資源,例如圖片,文檔等,程序中演示的目錄結構如下圖:

    ?這樣,本地的FTP服務站點就已經建好了,運行FTP服務器程序,然后點擊“啟動”按鈕后就啟動了FTP服務器,運行結果如下圖所示:

    然后配合上個專題中實現的FTP客戶端來完成與FTP服務器的“聊天”演示,因為FTP服務器程序中已經初始化用戶名和密碼(都為admin),所以FTP客戶端中取消選擇“匿名復選框”,直接輸入用戶名和密碼為admin后點擊“登錄”按鈕后就完成了用戶驗證的過程,并與FTP服務器建立了控制連接和數據連接。運行結果如下圖:

    當然用戶可以通過"上傳"、“下載”和刪除按鈕來對FTP服務器上的文件進行操作,這里就不貼出運行圖片了, 大家可以下載源碼來測試下的。

    ?

    六、內容的結尾,說說后面的計劃吧

    這個專題介紹完后,我這個C#網絡編程系列也就介紹完了,這個系列中主要介紹網絡編程的一些入門知識,對于朋友在留言中經常提到的“打洞”技術以及一些網絡編程中一些更難的內容還大家一起努力來學習的,同時我也會在后面和大家分享下一些實際開發過程中的網絡編程的內容(在后面的文章打算和大家分享一個下載器的實現),最后,希望這個系列可以讓大家對網絡協議有一個最初的入門,這樣在實際的開發過程中才知道這些實現背后的原理。之后我總結下我這個系列的所有文章的索引,以便讓大家更好的閱讀和查找關于這個系列的所有文章。

    ?

    源碼下載:http://files.cnblogs.com/zhili/FtpServer.zip,大家如果覺得不錯的話,還請大家推薦下,謝謝大家的支持

    ?用來演示的服務器目錄:http://files.cnblogs.com/zhili/MyFtpServerRoot.zip

    ?上個專題FTP文件上傳下載器源碼:http://files.cnblogs.com/zhili/FTPUpDownloader.zip

    ?

    ?

    轉載于:https://www.cnblogs.com/zhili/archive/2012/10/18/FTPServer.html

    總結

    以上是生活随笔為你收集整理的[C# 网络编程系列]专题十二:实现一个简单的FTP服务器的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。