2012年3月25日 星期日

使用 FLEX 連結 FTP Server 初探

最近公司的一個使用 Adobe AIR Runtime 製作的工具,需要包含上傳檔案的功能,由於檔案可能超出一般 http server 的上傳上限,或是等待時間。所以產生需要修改上傳模式的研究需求,想到的方式有兩個,第一種是將要上傳的檔案切割後分開上傳,在伺服器端將這些片斷拼回原來的檔案。而第二種方式則是改用本來就支援大檔案的傳輸協定,像是拿 FTP 取代 HTTP 傳輸檔案。

我負責的是後者,在網路上查詢了一些資料,發現一些網路上的範例有提到使用 Socket 和 FTP Server 建立連線,以資料串流的方式上傳檔案,並沒有發現 Flex framework 裡有提供類似 FtpClient 的類別可以使用。不過在嘗試理解範例的同時,發現一些似乎沒有寫完整的地方,讓人覺得有「規則沒講通」的感覺,為此花了一些時間去了解一下 FTP 的機制,在底下記錄一下已經理解的內容…


首先是 FTP 的傳輸特性,它由一開始就是設計來作為檔案傳輸的協定,在溝通上有兩種類型的連線(頻道),分別為「command channel(命令頻道)」和「data channel(資料頻道)」,前者用來發出命令以及取得命令的結果,後者則是資料的傳輸。以一般使用者的角度下認知的「保持連線狀態」指的是 command channel 仍在連線狀態中。但是實際上在一段時間沒有任何動作下,達到 Server 設定的閒置上限(timeout)後會被 Server 斷線,所以其實一些 FTP 軟體會在背後幫使用者作重新登入的動作。


猜想是因為不希望在资料傳輸的過程當中,將 Socket 的資料通道占滿,導致無法下任何命令。所以將之區分為 command channel 和 data channel 兩者,這樣就可以在正在傳輸檔案的時候,依然可以瀏覽資料夾或是進行其它動作。在目前的實作中,猜測可能可以容許同時有多個 data channel 來進行工作,不過還沒有進行測試。

在 Socket 的世界中只有「資料流」,由於網路硬體、頻寬…等因素影響,Socket 的資料傳輸並不保證接收端能夠一次接收到的資料量。所以在 command channel 中,每次接收到的資料並不保證就是「一個命令」,可能是某個命令的片斷,也可能是多個命令擠在一起。因此需要有個分隔字元來作區隔。在 FTP 裡是選擇使用 Linux 的換行字元「\n」來作為分隔,就像是坐在電腦前每輸入完一個指令後會按下「Enter」一樣。由此在 command channel 中可以判不同的命令和傳回值。

FTP 可以傳輸兩進位的資料,所以檔案中的某幾個位元,可能就剛好代表 command channel 用作分隔字元的「\n」,也就是說並沒有一個「安全的分隔字元」,因此比較保險的作法就是讓每個資料傳輸,都擁有自己獨立的 Socket 連線,這樣就沒有和其它資料混在一起的可能出現。因此才會猜測可能允許多個 data channel 並同時存在,由範例和觀察其它 FTP 軟體得知, data channel 只有在需要傳輸資料的時候才會建立,在資料傳輸完成後該連線就會關閉。

在觀察中讓我感覺比較意外的則是「目錄下的檔案清單」也是使用 data channel 傳遞,之前一直以為這種不帶特殊字元的資料,也會使用 command channel 傳回。後來想想也對,現在的檔名能放入字元越來越多,也不排除可能遇到具有大量檔案的資料夾,所以將檔案清單放在 data channel 傳遞的確是比較好的選擇。

記得之前上 Linux 課程的時候,老師有提到 FTP 的傳回值(command channel),是類似下面這種格式…
230 Login successful.
最前面的「230」是狀態碼,在隔一個空白後面,無論中間還有沒有其它的空白,所有內容都屬於描述,連線軟體主要由狀態碼得知命令結果,而描述大多是給人看的。畢竟沒有幾個人能背得起所有狀態碼所代表的意思。上面的例子中,230 就表示登入成功。

在某些情況下,描述對於連線軟體也是有意義的,像在底下的例子…
227 Entering Passive Mode (192,168,0,185,100,235).
這是表示 FTP Server 已經準備好接受建立 data channel,括號中前四個數字表示連線的 IP 是192.168.0.185,而後兩位則是代表要連線的 port 為︰100x256+235=25835。

另外每個命令所得到的狀態碼也並非唯一,像是「200」代表執行命令成功,不管是成功設定資料傳輸模式,還是成功設定資料字元編碼。不過在 command channel 裡,大多數的命令都需要等待 Server 回應才會進行下一個,採取一問一答的方式的對話。只要還記得剛下的指令是什麼,既使接到相同的狀態碼,也能夠清楚知道所代表的意思。

在我所知的網路的資料傳輸模式中,資料是被分割成一個一個的封包(package)後傳輸,而 TCP 模式可以確保在應用軟體接到資料的時候是維持原來的順序,但是並沒有一個機制去通知「資料已經傳送完畢」這件事,也因此我在看這個範例的時候,一直沒有找到有關通知 Server 檔案傳完的程式碼(也許有,只是我沒找到而已),也因此有這一連串的研究。

後來觀察其它 FTP 軟體所收到的訊息,發現檔資料傳輸完畢, command channel 會收到傳輸完畢的回應,經過實際撰寫程式後發現,原來是要「關閉 data channel」,FTP Server 在連線中斷後,就很順理成章的認為資料已經傳輸完成。也得到 data channel 在使用完畢就中斷(丢棄),下一次再重新建立的結論。

其實在測試的過程中,還有許多地方需要再進行測試、研究,像是如何作到斷點續傳,如何修改檔名,解決權限問題…等。而 Flex 程式也需要進行修改,才能在接收到一樣的狀態碼時,作出不同的反應。等到這部分的頭緒再理清楚後,再來分享心得…

沒有留言:

張貼留言