FTP的兩種傳輸模式的坑
- 2020 年 1 月 13 日
- 筆記
上周的系統遷移,進了一個坑,可謂真是坑,從問題的定位,到問題的解決,有很多值得借鑒、學習的,可以算是一次非常有價值的故障排查,

介紹一下背景,這是一套Tuxedo的服務,下圖所示,服務A調用服務B,其中服務A的功能是執行一定的邏輯生成個文件,服務B的功能是將文件推送至客戶FTP(Windows)服務器的指定路徑中,

這次搬遷的目的,是因為客戶的FTP服務器需要遷移升級,換了一台機器,但是IP不變,同時更新了FTP賬號的密碼,推送系統(服務A和B)未做任何變更,理論上,對推送端來說,是次很簡單的配合操作。
凡事不能亂立flag,越簡單的操作,可能蘊藏着你所不知的問題。當晚啟動新機器,推送端系統改了配置,執行測試,發現文件推送出現了問題,從服務A的日誌看,文件生成成功,異步調用服務B,未出現任何錯誤,但是服務B的日誌,未找到這次文件推送的請求,換句話說,從現象上看,服務A生成的文件,在調用下層服務B的過程中消失了?
一開始,沒找着頭緒,以至於嘗試了屢試不爽的重啟大法,還是無效。
其實,從ULOG日誌中,還是看得出一些端倪,他提示了服務B出現過server被kill,自動重啟的現象,

這個476的錯誤,從說明了解,應該就是server被kill,導致重啟,
476 WARN: Server groupid/serverid: client process processid: lost message Description A server died and the specified server (with group groupid and server identifier serverid) is recovering on its behalf. A message from the client with the specified processid has been lost. Additional information will be printed in subsequent messages Action No action required. See Also See Messages 477 and 478 below. 477 WARN: SERVICE=servicename MSG_ID=msgid REASON=server died Description A server died (see message 476) while processing service servicename. The client from which the message was sent is still active so a response message will be sent indicating the failure. Action No action required. 478 WARN: SERVICE=servicename MSG_ID=msgid REASON=server and client died Description A server died (see message 476) while processing service servicename. The client from which the message was sent is no longer active either so that a response message cannot be sent indicating the failure. Action No action required.
那麼現在的問題就是什麼原因導致服務B的server被kill進而重啟?
通過看出現問題的二進制文件,發現卡在了一個叫做putfile的函數上,程序用的FTP底層庫,有這段的邏輯,意思是在執行FTP的put文件指令時,會調用pasv函數,他會執行PASV指令,
int pasv(char *ip){ if(command("PASVrn") <= 0 ... } int putfile(char *name, char *ip){ if(t > 0) close(t); t = pasv(ip); ... }
這時,問題有些豁然開朗了,究其原因,如果了解FTP的朋友,就可能猜到,他可能和FTP的傳輸模式有關。
FTP是一種基於TCP的應用層協議,他不支持UDP協議。FTP工作在一種特殊的服務機制上,他使用兩個端口,一個「數據」端口和一個「命令」端口(也稱為控制端口)。通常情況下,端口21用作命令端口,端口20用作數據端口。然而,數據端口有時候並不是在端口20上時。因此,FTP的傳輸模式,可以分為兩種,主動模式,被動模式。
1. 主動模式
在主動模式的FTP中,客戶端從一個隨機的非系統端口(N>1023)連接到FTP服務器的命令端口端口21。然後,客戶端開始監聽端口N+1,並將FTP命令端口N+1告訴FTP服務器,「請把數據發送給我的N+1端口」。然後,服務器將從本地數據端口(端口20連接回客戶端的數據端口,也就是N+1端口。
因為服務器防火牆的隔離作用,我們應該確保服務器FTP到客戶端的一下幾個通道的暢通:
FTP服務器端口21(接受全部客戶端)
FTP服務器端口21到>1023的端口(服務器響應客戶端控制端口)
FTP服務器端口20到>1023的端口(服務器發起到客戶端的數據端口的連接)從>1023的端口到FTP服務器端口20(客戶端發送ack到服務器的數據端口)
用圖來表示這些通道:

第1步,客戶端的命令端口與服務器的命令端口連接並發送命令端口1027。然後,服務器在第2步時將一個ACK發送回客戶端的命令端口。第3步,服務器在其本地數據端口上啟動連接,連接到前面指定的客戶端的數據端口。最後,客戶端返回ACK,如第4步所示。
主動模式的FTP主要問題實際上落在客戶端。FTP的客戶端並不會主動連接到服務器的數據端口,而是是告訴服務器他正在監聽哪個端口,然後服務器發起連接到客戶端上指定的端口。但是,這樣的連接有時候會被客戶端的防火牆阻止。
2. 被動模式
為了解決服務器主動發起到客戶端連接會被阻止的問題,另一種更完善的工作模式出現了,他就是FTP的被動模式,縮寫作PASV,他工作的前提是客戶端明確告知FTP服務器他使用被動模式。
在被動模式的FTP中,客戶端啟動到服務器的兩個連接,解決了防火牆阻止從服務器到客戶端的傳入數據端口連接的問題。FTP連接建立後,客戶端在本地打開兩個隨機的非系統端口N和N+1(N>1023)。第一個端口連接服務器上的21端口,但是客戶端這次將會發出PASV命令,也就是不允許服務器連接回其數據端口。這樣,服務器隨後會打開一個隨機的非系統端口P(P>1023),並將P發送給客戶端作為PASV命令的響應。然後客戶端啟動從端口N+1到端口P的連接來傳輸數據。
在被動模式中,要保持一下通道的暢通:
FTP服務器的21端口(接受所有客戶端)
FTP服務器的21端口到>1023的遠程端口(服務器響應客戶端控制端口)
FTP服務器>1023的端口(接受所有客戶端發起的連接到服務器指定的隨機端口)
FTP服務器>1023的端口到>1023的遠程端口(服務器發送ack和數據到客戶端數據端口)
被動模式用圖表示:

第1步,客戶端在命令端口上與服務器連接,並發出PASV命令。然後,服務器在第2步時使用端口2024進行響應,告訴客戶端他正在監聽的數據連接端口。第3步,客戶端啟動從其數據端口到指定服務器數據端口的數據連接。最後,服務器在第4步將ACK發送回客戶端的數據端口。
服務器防火牆需要給FTP的被動模式開放一個端口範圍允許所有客戶端連接,比如5000 – 6000。
因此,從現象以及代碼,服務B的卡頓,確實可能和被動模式有關,通過服務B進行FTP傳輸,首先設置了PASV,然後hang住,說明可能當前的環境,不支持被動模式。另一個角度,通過命令行驗證,在客戶端服務器,執行ftp命令,不輸入任何參數的情況下,put文件正常,但是當執行了pasv,此時命令行hang了。
因為服務端的FTP是通過Windows自帶FTP功能搭建的,並不是通過一些常見的FTP工具做的,Windows服務器的設置,自己不是很熟,網上搜了下,有的說是在服務器管理器-FTP防火牆支持中,設置數據通道端口範圍,就可以配置被動的模式,

但是,客戶主機工程師通過如下配置,設置被動模式,不覺明歷,
1. sc sidtype ftpsvc unrestricted(將ftp服務的註冊卸載) 2.net stop ftpsvc & net start ftpsvc(重啟ftp服務) 3.netsh advfirewall firewall add rule name="FTP for IIS7" service=ftpsvc action=allow protocol=TCP div=in(開啟所有ftp端口監聽) 4.netsh advfirewall set global Statefulftp disable(使防火牆不攔截所有ftp服務的訪問)
執行測試,此時服務A和B,能配合推送FTP文件,這才算是從坑中跳出來。
對開放系統來說,一個問題的解決,往往蘊涵著很多關聯的知識,一方面能找到問題的突破口(通過日誌、pstack、gdb等指令定位問題),另一方面能由點及面的武裝自己的知識庫(FTP的傳輸模式有何區別、如何設置不同的傳輸模式),這些可能都是需要在日常工作和學習中積累和沉澱的。
其實,對個人來說,碰到問題是好事,但前提是能積累這些問題,無論是誰的經驗,能融會貫通,轉成自己的知識,同一個坑,不要進入兩次,就很有價值了。