端配置與排錯(cuò))
簡介PCMans FTP Server 是一款面向初學(xué)者的開源輕量級(jí) FTP 服務(wù)端軟件目標(biāo)是讓不熟悉網(wǎng)絡(luò)配置的使用者也能快速完成基本服務(wù)器的搭建設(shè)計(jì)上以簡單易用為先功能與安全性并非重點(diǎn)適合剛接觸 FTP 協(xié)議、希望了解服務(wù)端工作原理的入門者與自學(xué)者。壓縮包共 143 個(gè)文件、約 154KB主體是 VC 工程源碼34 個(gè) cpp 與 39 個(gè) h 文件構(gòu)成服務(wù)端核心邏輯涉及命令解析、用戶管理與主框架界面43 個(gè) ini 及 rc、bmp、ico 等資源文件承載界面配置與圖標(biāo)位圖另有 dsp、dsw、clw 等工程與類向?qū)募芍苯佑?Visual C 打開編譯。該資源已有 204 人學(xué)習(xí)下載讀者可由此獲得一套可運(yùn)行的 FTP 服務(wù)端完整實(shí)現(xiàn)對(duì)照源碼理解連接建立、命令響應(yīng)與用戶權(quán)限控制的處理流程也可在其基礎(chǔ)上裁剪擴(kuò)展作為課程設(shè)計(jì)、協(xié)議學(xué)習(xí)與 MFC 界面實(shí)踐的參考樣本。1. PCMans FTP Server一個(gè)不用安裝的開源 FTP 服務(wù)端能解決什么某次在內(nèi)網(wǎng)給幾臺(tái)設(shè)備刷升級(jí)包手邊只有一臺(tái) Windows 機(jī)器沒有外網(wǎng)也不允許裝需要授權(quán)的服務(wù)端。先試的是系統(tǒng)自帶的 FTP 角色角色裝上、站點(diǎn)建好、授權(quán)配完客戶端連上去還是一句 530。最后救場的是一份一百多 KB 的開源軟件——PCMans FTP Server解壓雙擊就能當(dāng)服務(wù)端使。這類開源軟件在 Windows 上不算多見不寫注冊表、不裝運(yùn)行庫、不駐留后臺(tái)服務(wù)從老版本 Windows 到現(xiàn)在的桌面版和服務(wù)器版都能開起來。裝順了它就是一臺(tái)隨身的文件交換站裝不順時(shí)現(xiàn)象也很集中——能登錄卻列不出目錄、大文件傳一半斷掉、中文名全變問號(hào)。它適合內(nèi)網(wǎng)分發(fā)、設(shè)備取包、臨時(shí)給同事傳大文件這類活要域名、虛擬主機(jī)、強(qiáng)制加密那一套的它接不住。裝之前先想清楚一件事這東西小但小不等于沒有前置條件。端口、防火墻、被動(dòng)模式端口段、NTFS 權(quán)限缺一個(gè)就是半小時(shí)的排查。2. 裝前清單Windows 版本、21 端口與被動(dòng)端口段怎么定很多人拿到這個(gè) exe 的第一反應(yīng)是雙擊、建賬號(hào)、發(fā)地址然后在客戶端那邊卡住回頭懷疑軟件有問題。實(shí)際上絕大多數(shù)「連不上」都不是軟件的問題而是裝之前沒把三件事定下來跑在哪個(gè)系統(tǒng)上、用哪個(gè)端口、數(shù)據(jù)目錄給誰讀寫。這一章把這三件事按順序捋一遍后面的步驟才好往下走。2.1 運(yùn)行環(huán)境它到底依賴哪些東西它是原生的 Win32 程序這一點(diǎn)很關(guān)鍵。不需要 .NET Framework不需要 VC 運(yùn)行庫不需要 Java也不需要先裝什么「服務(wù)端框架」。這也是它在老機(jī)器、封閉內(nèi)網(wǎng)、臨時(shí)救急場景里特別順手的原因——拷過去就能開不用先聯(lián)網(wǎng)下一堆依賴。程序本身是 32 位的在 64 位系統(tǒng)上照樣跑不會(huì)有什么兼容層的問題。系統(tǒng)覆蓋范圍從 Windows XP SP3 一直到現(xiàn)在的桌面版和服務(wù)器版都能用。硬件要求基本可以忽略幾十 MB 內(nèi)存、幾百 KB 磁盤就能撐住十幾個(gè)人的小流量。網(wǎng)上流傳最廣的版本是 2.0.7這個(gè)項(xiàng)目本身早就停止更新了所以不必去追什么「最新版」——它沒有活躍的迭代分支你看到的各種版本號(hào)差別往往只是漢化包和打包方式不同。項(xiàng)目要求說明操作系統(tǒng)Windows XP SP3 及以上桌面版、服務(wù)器版均可32/64 位系統(tǒng)都行運(yùn)行庫無不需要 .NET、VC、Java磁盤占用幾百 KB程序本體極小空間主要留給數(shù)據(jù)目錄內(nèi)存占用幾十 MB 量級(jí)隨并發(fā)連接數(shù)增長個(gè)人用途壓力很小權(quán)限普通用戶可運(yùn)行只有加防火墻規(guī)則、注冊服務(wù)需要管理員網(wǎng)絡(luò)一個(gè)固定內(nèi)網(wǎng) IP建議手工配靜態(tài)地址別用自動(dòng)獲取需要提醒的是老程序在新系統(tǒng)上的顯示問題高 DPI 屏幕上界面可能發(fā)虛窗口不會(huì)自動(dòng)縮放。這不影響功能別把它當(dāng)成裝壞了。2.2 端口規(guī)劃21、被動(dòng)端口段和防火墻規(guī)則FTP 跟普通 Web 服務(wù)最大的區(qū)別是它用兩條連接一條控制連接走命令和返回碼一條數(shù)據(jù)連接專門搬文件。數(shù)據(jù)連接有兩種建立方式主動(dòng)模式下由服務(wù)端回頭連客戶端被動(dòng)模式下由服務(wù)端開一個(gè)端口等客戶端來連。前者在客戶端位于 NAT 后面時(shí)基本必掛所以真正要配的是被動(dòng)模式也就是常說的 PASV 端口段。控制端口默認(rèn) 21。Windows 并不限制普通用戶綁定 1024 以下的端口所以哪怕不用管理員身份也能綁上 21但如果這臺(tái)機(jī)器上還跑著別的 FTP 組件21 會(huì)被占那就換 2121 之類的端口客戶端連的時(shí)候顯式指定即可。被動(dòng)端口段別劃太大十個(gè)就夠十幾個(gè)人用劃成 50000-50009 這種連續(xù)區(qū)間最省事防火墻規(guī)則也好寫。# 管理員身份執(zhí)行放行控制端口和被動(dòng)數(shù)據(jù)端口段 netsh advfirewall firewall add rule namePCManFTP-Ctrl dirin actionallow protocolTCP localport21 netsh advfirewall firewall add rule namePCManFTP-PASV dirin actionallow protocolTCP localport50000-50009 # 確認(rèn)端口已經(jīng)被監(jiān)聽第二列是本地地址最后一列是進(jìn)程 PID netstat -ano | findstr :21第一條規(guī)則管登錄和命令交互第二條管文件傳輸。dirin表示入站方向actionallow是放行l(wèi)ocalport可以直接寫區(qū)間這是 netsh 比較省事的地方不用一條一條加。規(guī)則名自己起起完以后用netsh advfirewall firewall show rule namePCManFTP-PASV能回查刪的時(shí)候按名字刪別去翻圖形界面找。netstat那條是裝完必跑的確認(rèn)動(dòng)作。如果 21 端口沒有出現(xiàn)在 LISTENING 狀態(tài)說明服務(wù)端根本沒起來或者綁到了別的地址上這時(shí)候去查防火墻是白費(fèi)功夫。真遇到端口被占用用netstat -ano | findstr :21拿到最后一列的 PID再tasklist | findstr PID就知道是哪個(gè)進(jìn)程搶的。提示不要為了「排除問題」直接把防火墻整個(gè)關(guān)掉。關(guān)掉只能證明問題出在防火墻上證明不了是哪個(gè)端口排查完還得一條條加回來來回折騰。2.3 目錄與身份別用管理員賬號(hào)跑服務(wù)數(shù)據(jù)目錄的選擇比想象中重要。我一般單獨(dú)劃一個(gè)目錄比如D:\ftp下面分root對(duì)外可見的根和upload收文件的地方。三個(gè)地方堅(jiān)決不放用戶目錄下的 Desktop 和 Downloads因?yàn)闄?quán)限繼承混亂、清理時(shí)容易誤刪網(wǎng)盤同步目錄同步客戶端會(huì)持續(xù)占用文件句柄FTP 寫入時(shí)報(bào)共享沖突屬于典型的玄學(xué)問題以及含中文或空格的路徑老程序?qū)捵址窂降奶幚聿⒉粐?yán)謹(jǐn)這是踩過坑之后定下來的規(guī)矩。身份也要單獨(dú)給。不要用 Administrator 或者當(dāng)前登錄的管理員賬號(hào)跑服務(wù)一旦目錄權(quán)限配錯(cuò)等于把整臺(tái)機(jī)器的寫權(quán)限開放出去了。建一個(gè)專用本地賬號(hào)只對(duì)這個(gè)數(shù)據(jù)目錄有修改權(quán)限其他盤一概不給。建目錄和授權(quán)兩條命令就能搞定。# 建一個(gè)只碰 FTP 數(shù)據(jù)目錄的本地賬號(hào) $p ConvertTo-SecureString ChangeThis_2024! -AsPlainText -Force New-LocalUser -Name ftpsvc -Password $p -PasswordNeverExpires -Description FTP data account New-Item -ItemType Directory -Force -Path D:\ftp\root,D:\ftp\upload | Out-Null # (OI) 對(duì)象繼承、(CI) 容器繼承、M 修改權(quán)限、/T 遞歸到子目錄 icacls D:\ftp /grant ftpsvc:(OI)(CI)M /TPasswordNeverExpires這一項(xiàng)別省。服務(wù)化之后如果這個(gè)賬號(hào)的密碼到期服務(wù)會(huì)靜默啟動(dòng)失敗表現(xiàn)出來就是「昨天還好好的今天連不上」而且日志里什么都不會(huì)寫非常難查。icacls里的(OI)和(CI)是讓權(quán)限往下繼承不加這兩個(gè)參數(shù)只對(duì)當(dāng)前目錄生效子目錄里的文件照樣寫不進(jìn)去。給M修改而不是F完全控制是因?yàn)橥耆刂评锇臋?quán)限的能力沒必要給。3. 從解壓到第一個(gè)賬號(hào)PCMans FTP Server 的落地步驟環(huán)境定完就可以動(dòng)手了。這一章的節(jié)奏是先把文件放對(duì)地方再啟動(dòng)看界面然后建第一個(gè)能登錄的賬號(hào)最后處理「重啟之后它不自己起來」這個(gè)必然會(huì)遇到的問題。每一步都有可以回退的檢查點(diǎn)別一口氣全做完再測。3.1 落地目錄程序和數(shù)據(jù)分開放下載下來一般是個(gè)壓縮包解開之后是主程序和可能附帶的語言文件、說明文檔。把整個(gè)文件夾一起搬到D:\apps\pcmanftp不要只挑那個(gè) exe 拷出來——有些打包版本帶語言文件缺了會(huì)變成英文界面功能不受影響但配置項(xiàng)看著費(fèi)勁。程序目錄定下來之后就別再挪了。這類綠色程序的配置通常跟著程序目錄走賬號(hào)的主目錄路徑、端口、限速這些設(shè)置都存在旁邊路徑一變之前配的賬號(hào)主目錄很可能全部失效表現(xiàn)是登錄成功但目錄是空的。這也是我建議一開始就用固定路徑的原因別圖省事放在桌面臨時(shí)跑一下。另外不要放在C:\Program Files底下。那個(gè)目錄受 UAC 保護(hù)程序?qū)懪渲玫臅r(shí)候會(huì)被重定向或者直接失敗表現(xiàn)是「設(shè)置改完重啟就還原」很容易誤判成軟件 bug。3.2 首次啟動(dòng)托盤圖標(biāo)、主窗口和日志窗雙擊主程序任務(wù)欄右下角會(huì)出現(xiàn)一個(gè)托盤圖標(biāo)雙擊它才彈出主窗口。界面上大致分三塊賬號(hào)管理、目錄或虛擬目錄設(shè)置、以及一個(gè)滾動(dòng)的日志窗。第一次啟動(dòng)時(shí)默認(rèn)沒有任何正式賬號(hào)匿名訪問可能是開著的也可能是關(guān)著的取決于打包版本的默認(rèn)配置所以第一步先去看賬號(hào)列表別急著發(fā)地址給同事。日志窗是這個(gè)軟件最有價(jià)值的排錯(cuò)入口比任何第三方抓包工具都直接??蛻舳诉B上來之后它會(huì)把收到的命令和服務(wù)端返回的碼逐行打出來USER、PASS、PWD、PASV、LIST、RETR哪一步斷的一目了然。養(yǎng)成習(xí)慣——客戶端報(bào)錯(cuò)的第一時(shí)間不是去改配置而是先看日志窗停在哪一行。如果雙擊之后托盤沒有圖標(biāo)先懷疑端口占用。有些機(jī)器上裝過別的 FTP 組件21 被占了程序啟動(dòng)時(shí)綁定失敗但界面不一定彈提示。這時(shí)候用 2.2 節(jié)那條netstat查一下或者干脆先把控制端口改成 2121 試一次能起來就說明是端口沖突。3.3 建第一個(gè)賬號(hào)主目錄、權(quán)限位和密碼建賬號(hào)這一步建議保守一點(diǎn)第一次只開讀權(quán)限確認(rèn)能登錄能列目錄能下載再把寫權(quán)限加上去。一次性把權(quán)限全打開出了問題分不清是認(rèn)證的問題還是權(quán)限的問題。參數(shù)建議值原因用戶名純英文加數(shù)字中文和空格在部分老客戶端上會(huì)解析出錯(cuò)密碼12 位以上混合字符這類輕量服務(wù)端沒有防暴力破解機(jī)制主目錄D:\ftp\root或每人一個(gè)子目錄多人的時(shí)候分目錄刪庫不至于全沒初始權(quán)限只勾讀取和列目錄先驗(yàn)證通路再逐步放開匿名訪問默認(rèn)關(guān)閉內(nèi)網(wǎng)也不建議長期開著密碼這件事值得單獨(dú)說一句。很多人裝完隨手設(shè)個(gè)ftp或者123456覺得反正是內(nèi)網(wǎng)。但內(nèi)網(wǎng)里通常還掛著打印機(jī)、攝像頭、各種默認(rèn)口令的設(shè)備一臺(tái)機(jī)器被當(dāng)成跳板之后第一個(gè)被掃的就是這種無防護(hù)的 FTP。設(shè)一個(gè)正經(jīng)密碼成本幾乎為零。建完之后立刻用客戶端連一次別等到配完限速、虛擬目錄、服務(wù)化之后再測。一次只改一個(gè)變量出問題才知道是哪個(gè)改動(dòng)引起的。3.4 無人值守把它注冊成 Windows 服務(wù)托盤程序的固有問題注銷之后進(jìn)程跟著會(huì)話結(jié)束機(jī)器重啟后不會(huì)自動(dòng)起來遠(yuǎn)程桌面斷開連接時(shí)間長了也可能被回收。放在自己電腦上臨時(shí)用無所謂放在一臺(tái)專門的文件交換機(jī)上就必須解決。常見做法是用 nssm 這類服務(wù)包裝器把托盤程序包成一個(gè)標(biāo)準(zhǔn)的 Windows 服務(wù)。# 把主程序注冊成服務(wù)指定工作目錄設(shè)置自動(dòng)啟動(dòng)和異常重啟 nssm install PCManFTP D:\apps\pcmanftp\PCManFTPd.exe nssm set PCManFTP AppDirectory D:\apps\pcmanftp nssm set PCManFTP Start SERVICE_AUTO_START nssm set PCManFTP AppExit Default Restart nssm set PCManFTP ObjectName .\ftpsvc ChangeThis_2024! nssm start PCManFTPAppDirectory必須設(shè)因?yàn)槌绦驎?huì)去當(dāng)前工作目錄找配置文件不設(shè)的話服務(wù)起來讀的是C:\Windows\System32配置全是空的表現(xiàn)就是「服務(wù)在跑但賬號(hào)全沒了」。AppExit Default Restart讓它在異常退出時(shí)自動(dòng)拉起對(duì)付偶發(fā)的崩潰有用。ObjectName指定用剛才建的那個(gè)低權(quán)限賬號(hào)跑服務(wù)不要用 LocalSystem理由和 2.3 節(jié)一樣。注意服務(wù)化之后托盤圖標(biāo)不再出現(xiàn)界面里改的配置有可能不落到服務(wù)實(shí)例上或者被服務(wù)重啟覆蓋。正確順序是先在界面里把賬號(hào)、端口、限速全部調(diào)好、測通最后再注冊服務(wù)之后所有改動(dòng)走配置文件不要再依賴界面。4. 配置逐項(xiàng)摳權(quán)限位、虛擬目錄、限速與中文編碼到這一步服務(wù)已經(jīng)能跑、賬號(hào)已經(jīng)能登剩下的就是把參數(shù)調(diào)到一個(gè)長期不惹事的狀態(tài)。這一章的四組配置項(xiàng)前兩組決定「誰能干什么」后兩組決定「出事的時(shí)候損失多大」。每一項(xiàng)都說清楚為什么這么設(shè)方便你按自己的場景改。4.1 六個(gè)權(quán)限位勾選之前先想清楚誰在用賬號(hào)的權(quán)限是一組復(fù)選框看著簡單但組合出來的效果差別很大。核心是區(qū)分「發(fā)文件」和「收文件」兩類場景不要一律全勾。權(quán)限位作用什么場景給列表/瀏覽能看見目錄里有什么幾乎所有場景都要給不給就是登錄成功但一片空白讀取/下載能把文件取走分發(fā)升級(jí)包、共享資料時(shí)給寫入/上傳能往目錄里放新文件收包場景給注意不能覆蓋同名文件追加能在已有文件末尾續(xù)寫斷點(diǎn)續(xù)傳需要風(fēng)險(xiǎn)是磁盤被慢慢撐滿刪除能刪文件只給維護(hù)賬號(hào)普通收發(fā)賬號(hào)不給重命名能改文件名同上改名的破壞力常被低估三個(gè)典型組合可以直接抄只發(fā)不收的賬號(hào)給「列表 讀取」客戶端只能下載不能動(dòng)手只收不發(fā)的賬號(hào)給「列表 寫入 建目錄」不給刪除和重命名這樣對(duì)方傳錯(cuò)了你還能救回來雙向交換的賬號(hào)才全開但同時(shí)要配上磁盤配額或者在目錄所在分區(qū)留足余量。追加權(quán)限單獨(dú)提一下它是斷點(diǎn)續(xù)傳的前提但也是唯一一個(gè)能讓單個(gè)文件無限增長的權(quán)限。如果開給了外部設(shè)備最好在數(shù)據(jù)目錄上掛一個(gè)磁盤配額或者用計(jì)劃任務(wù)定期清理超期文件。4.2 虛擬目錄把三塊盤拼成一棵樹一個(gè)賬號(hào)只有一個(gè)主目錄這是硬限制。虛擬目錄解決的就是這個(gè)把別的物理路徑掛成主目錄下的一個(gè)名字客戶端看到的是一個(gè)連續(xù)的目錄樹實(shí)際文件散落在不同磁盤上。最典型的用法是主目錄放只讀的發(fā)布包D:\ftp\root上傳目錄單獨(dú)放一塊大容量盤E:\incoming掛成root/upload??蛻舳说卿浿罂吹降木褪且粋€(gè)目錄不用關(guān)心后面是幾塊盤。另一個(gè)好處是不暴露真實(shí)盤符結(jié)構(gòu)少一點(diǎn)信息泄露。掛載的時(shí)候有兩個(gè)坑。一是掛載點(diǎn)名字不要和主目錄里已有的真實(shí)子目錄重名沖突時(shí)的行為不好預(yù)期有的版本會(huì)讓真實(shí)目錄直接不可見。二是虛擬目錄如果指向 UNC 路徑\\某主機(jī)\共享名而服務(wù)是用本地賬號(hào)跑的會(huì)因?yàn)槟貌坏骄W(wǎng)絡(luò)憑據(jù)而訪問失敗日志里表現(xiàn)為列目錄超時(shí)或者 550。這種場景要么把服務(wù)登錄賬戶換成有共享權(quán)限的賬號(hào)要么先把共享映射成本地盤再掛。4.3 限速、連接數(shù)與超時(shí)小機(jī)器的自保參數(shù)這組參數(shù)平時(shí)沒存在感出問題的時(shí)候就是整臺(tái)機(jī)器被拖死。估算方法很簡單先看上行帶寬再除以單個(gè)人愿意接受的傳輸速度。10 Mbps 上行、單人給 2 Mbps那就是五個(gè)人同時(shí)傳設(shè)成 8 留點(diǎn)余量。最大連接數(shù)按上面的估算填別拍腦袋填 100。超出的連接會(huì)被拒客戶端表現(xiàn)是「有時(shí)候能連有時(shí)候不能」。單 IP 連接數(shù)建議 2 到 3。多線程下載工具默認(rèn)會(huì)開五到十條連接不限的話一個(gè)人就能把隊(duì)列占滿。上傳/下載限速單位通常是 KB/s填的時(shí)候注意別把 KB 當(dāng) Kb差八倍。空閑超時(shí)60 到 300 秒之間。太短會(huì)把正在思考人生的客戶端踢掉太長會(huì)讓半死的連接一直占著名額。還有一個(gè)容易忽略的聯(lián)動(dòng)被動(dòng)端口段的大小必須大于等于最大連接數(shù)。只劃了 5 個(gè)端口卻允許 20 個(gè)連接同時(shí)傳文件的時(shí)候就會(huì)有一部分人連不上數(shù)據(jù)連接現(xiàn)象是能登錄、能列目錄、下載卡住不動(dòng)。這個(gè)坑非常隱蔽因?yàn)榭刂七B接一切正常。4.4 中文亂碼GBK 還是 UTF-8亂碼是這個(gè)軟件被抱怨最多的地方但根源不在軟件在 FTP 協(xié)議本身??刂七B接默認(rèn)沒有規(guī)定字符編碼各家客戶端各按各的理解來Windows 資源管理器按系統(tǒng)本地編碼簡體中文環(huán)境是 GBK解釋很多第三方客戶端默認(rèn)按 UTF-8 解釋。同一個(gè)目錄換個(gè)客戶端打開就是一堆問號(hào)。服務(wù)端如果提供編碼選項(xiàng)優(yōu)先選 UTF-8這是現(xiàn)在的主流。但如果客戶端里有老設(shè)備——嵌入式系統(tǒng)、老版本的系統(tǒng)自帶客戶端——它們只會(huì)按本地編碼走那就只能退回 GBK兩邊不能同時(shí)滿足。折中做法是干脆繞開這個(gè)問題目錄名和文件名全部用英文數(shù)字加下劃線中文只出現(xiàn)在文件內(nèi)容里。我現(xiàn)在所有 FTP 目錄都是這個(gè)規(guī)矩省下來的排查時(shí)間遠(yuǎn)比改名的麻煩多。真要用中文名就固定一種客戶端別今天用資源管理器明天用別的工具然后懷疑服務(wù)端壞了。5. 踩坑排查能登錄卻列不出目錄的五個(gè)原因下面五條是這套環(huán)境里出現(xiàn)頻率最高的故障按「現(xiàn)象、原因、解決」寫遇到問題時(shí)按順序?qū)μ?hào)入座。每一條都對(duì)應(yīng)前面某一節(jié)的配置項(xiàng)回頭改就行。5.1 能登錄、目錄列不出來現(xiàn)象客戶端提示登錄成功命令行里敲ls卡十幾秒最后報(bào)數(shù)據(jù)連接建立失敗圖形客戶端表現(xiàn)為一直轉(zhuǎn)圈然后空白。原因九成是被動(dòng)模式端口段沒有放行。控制連接走的是 21通的數(shù)據(jù)連接要連 50000 段被防火墻攔了。剩下的一成是服務(wù)端返回的 PASV 地址是內(nèi)網(wǎng) IP而客戶端在另一個(gè)網(wǎng)段連過去自然不通。解決先按 2.2 節(jié)把 PASV 段加到防火墻規(guī)則里重試。還不行就判斷是不是跨網(wǎng)段把客戶端放到同一網(wǎng)段測一次通就說明是地址回填的問題服務(wù)端有對(duì)外 IP 填寫項(xiàng)就填上沒有就只能在同網(wǎng)段使用或者做端口映射時(shí)把 PASV 段一起映射。5.2 輸入賬號(hào)密碼一直 530現(xiàn)象用戶名密碼明明是對(duì)的返回 530 登錄失敗。原因按可能性排序——賬號(hào)沒有啟用很多版本新建賬號(hào)默認(rèn)是停用狀態(tài)賬號(hào)的主目錄路徑寫錯(cuò)了或者目錄被刪了路徑不存在時(shí)認(rèn)證階段就會(huì)被拒密碼里帶了特殊字符在某些配置文件里被截?cái)噙B接數(shù)達(dá)到上限新連接直接被拒。解決先看日志窗服務(wù)端到底收到了什么用戶名如果連USER都沒打印出來問題在客戶端打印了但緊跟著 530就去核對(duì)主目錄是否存在。密碼先用純字母數(shù)字試一次能進(jìn)就說明是特殊字符的問題換掉即可。5.3 傳大文件傳一半就斷現(xiàn)象幾十 MB 的包傳到六成左右斷掉重傳又從零開始。原因空閑超時(shí)設(shè)得太短傳輸過程中控制連接長時(shí)間沒有命令往來被判定空閑磁盤空間不足殺毒軟件的實(shí)時(shí)掃描鎖住了正在寫入的文件網(wǎng)絡(luò)本身抖動(dòng)。解決先把超時(shí)調(diào)到 300 秒再試這是最常見的一條。然后看數(shù)據(jù)目錄所在分區(qū)的剩余空間。還斷就把數(shù)據(jù)目錄從實(shí)時(shí)掃描的范圍里排除這條要按自己環(huán)境的策略評(píng)估別一刀切。最后才懷疑網(wǎng)絡(luò)方法是同一臺(tái)機(jī)器本地回環(huán)測一次本地不斷說明是鏈路問題。5.4 中文文件名變成問號(hào)現(xiàn)象用系統(tǒng)資源管理器打開中文目錄全是問號(hào)換成別的客戶端又正常。原因控制連接的編碼不一致一端按 GBK 發(fā)一端按 UTF-8 解。這不是權(quán)限問題也不是文件系統(tǒng)問題改權(quán)限改目錄都無效。解決統(tǒng)一編碼服務(wù)端和客戶端選同一種。做不到統(tǒng)一就把文件名改成英文見 4.4 節(jié)。別在這上面反復(fù)重裝軟件重裝一百次結(jié)果一樣。5.5 重啟之后服務(wù)沒自己起來現(xiàn)象手動(dòng)雙擊能用機(jī)器一重啟就連不上登錄機(jī)器一看托盤圖標(biāo)也沒有。原因托盤程序本來就不是服務(wù)開機(jī)自啟項(xiàng)有時(shí)也不生效已經(jīng)服務(wù)化的常見是服務(wù)賬戶密碼到期、或者賬戶沒有「作為服務(wù)登錄」的權(quán)限服務(wù)啟動(dòng)失敗但系統(tǒng)不彈提示。解決用 3.4 節(jié)的方式注冊服務(wù)賬戶密碼設(shè)成永不過期給 nssm 配上輸出重定向把標(biāo)準(zhǔn)輸出和錯(cuò)誤寫到文件里服務(wù)起不來的時(shí)候那個(gè)文件里會(huì)有直接原因比翻系統(tǒng)日志快得多。6. 裝完怎么驗(yàn)三條命令、一張對(duì)照表和我的收尾習(xí)慣裝完不等于裝好。我的標(biāo)準(zhǔn)是換一臺(tái)機(jī)器、用另一種客戶端、走一遍完整的上傳下載、校驗(yàn)哈希一致這才算交付。下面這套冒煙流程十分鐘能走完但能擋掉后面八成的問題。6.1 三條命令走完一輪冒煙第一條驗(yàn)登錄和列目錄重點(diǎn)是把被動(dòng)模式開關(guān)各試一次。同一條命令UsePassive設(shè) true 通、設(shè) false 不通基本可以確定是 NAT 或防火墻方向的問題而不是賬號(hào)問題。# 冒煙一登錄并列出根目錄true 走 PASVfalse 走 PORT各跑一次對(duì)比 $cred New-Object System.Net.NetworkCredential(ftpuser,YourPass123) $req [System.Net.FtpWebRequest]::Create(ftp://192.168.1.20/) $req.Method [System.Net.WebRequestMethodsFtp]::ListDirectory $req.Credentials $cred $req.UsePassive $true # 關(guān)鍵變量換成 false 再跑一次 $req.Timeout 10000 # 控制連接超時(shí)單位毫秒 $resp $req.GetResponse() (New-Object System.IO.StreamReader($resp.GetResponseStream())).ReadToEnd() $resp.Close()第二條驗(yàn)寫權(quán)限和磁盤空間傳一個(gè)幾十 MB 的文件別用小文件小文件測不出超時(shí)和限速的問題。# 冒煙二上傳一個(gè)真實(shí)大小的文件 $up [System.Net.FtpWebRequest]::Create(ftp://192.168.1.20/upload/test.bin) $up.Method [System.Net.WebRequestMethodsFtp]::UploadFile $up.Credentials $cred $up.UseBinary $true # 必須開否則換行符會(huì)被轉(zhuǎn)換哈希對(duì)不上 $up.UsePassive $true $bytes [System.IO.File]::ReadAllBytes(D:\tmp\test.bin) $s $up.GetRequestStream() $s.Write($bytes, 0, $bytes.Length) $s.Close() $up.GetResponse().Close()UseBinary這一項(xiàng)千萬別漏。文本模式下客戶端會(huì)做換行符轉(zhuǎn)換傳上去的文件大小和哈希都會(huì)變?nèi)缓竽銜?huì)以為是傳輸壞了其實(shí)是模式選錯(cuò)了。第三條是哈希比對(duì)兩端各算一次值一樣才算真正傳對(duì)了。# 冒煙三服務(wù)端和客戶端各跑一次比對(duì) SHA256 certutil -hashfile D:\ftp\upload\test.bin SHA256 certutil -hashfile D:\tmp\test.bin SHA2566.2 一張驗(yàn)收對(duì)照表檢查項(xiàng)動(dòng)作期望結(jié)果端口監(jiān)聽netstat -ano | findstr :21狀態(tài)為 LISTENINGPID 是主程序被動(dòng)端口客戶端強(qiáng)制 PASV 傳輸數(shù)據(jù)連接建立成功無超時(shí)登錄認(rèn)證錯(cuò)誤密碼試一次返回 530日志窗有記錄讀權(quán)限下載一個(gè)文件并比對(duì)哈希哈希一致寫權(quán)限上傳一個(gè)文件目錄中出現(xiàn)且大小一致權(quán)限邊界用只讀賬號(hào)嘗試上傳被拒絕返回 550 類錯(cuò)誤中文名建一個(gè)中文名目錄再訪問客戶端顯示正?;虬醇s定全英文重啟演練重啟機(jī)器后直接連接無需人工干預(yù)即可登錄倒數(shù)第二行那個(gè)「權(quán)限邊界」最容易被跳過。只測了「能做的都能做」沒測「不能做的確實(shí)做不了」等于權(quán)限配置根本沒驗(yàn)證過。用一個(gè)只讀賬號(hào)去傳一次被明確拒絕才說明權(quán)限位生效了。6.3 我的收尾習(xí)慣從那以后我每次交付這類環(huán)境都要強(qiáng)制走一遍「換機(jī)驗(yàn)證 重啟演練」。換機(jī)驗(yàn)證是拿一臺(tái)沒參與過配置的機(jī)器當(dāng)客戶端避免把配置機(jī)的緩存和環(huán)境變量當(dāng)成理所應(yīng)當(dāng)重啟演練是直接重啟一次服務(wù)器不做任何人工操作就看能不能連上——服務(wù)化配得對(duì)不對(duì)只有這一步能驗(yàn)出來。另外兩個(gè)小習(xí)慣一是把日志窗的輸出定期留檔出問題的時(shí)候能倒推出是哪天哪個(gè) IP 傳了什么二是數(shù)據(jù)目錄所在分區(qū)的剩余空間掛個(gè)提醒FTP 這種長期無人看守的服務(wù)最后出問題十有八九是磁盤滿了而不是軟件壞了。這套東西不復(fù)雜把該配的配到位、該驗(yàn)的驗(yàn)一遍剩下的就是讓它安靜地跑著。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取