07-1. FTP 協定:檔案傳輸協定
深入理解 FTP 主動被動模式與檔案傳輸原理
目錄
📁 FTP 協定:檔案傳輸協定
🎯 什麼是 FTP?
💡 比喻:網路硬碟
像 USB 隨身碟一樣,可以在電腦之間傳輸檔案
但透過網路,不需要實體接觸FTP(File Transfer Protocol) 是一種用於在網路上傳輸檔案的標準協定,誕生於 1971 年,是網際網路最古老的協定之一。
為什麼需要 FTP?
HTTP vs FTP:
| 特性 | HTTP | FTP |
|---|---|---|
| 主要用途 | 網頁瀏覽 | 檔案傳輸 |
| 連線方式 | 單一連線 | 雙連線(控制+數據) |
| 續傳 | ⚠️ 需特殊處理 | ✅ 內建支援 |
| 目錄瀏覽 | ❌ 無 | ✅ 有 |
| 權限管理 | ⚠️ 有限 | ✅ 完整 |
| 適用場景 | 下載軟體、瀏覽網頁 | 網站部署、備份 |
FTP 使用場景:
- 🌐 網站部署(上傳 HTML/CSS/JS)
- 💾 大檔案傳輸(影片、備份檔)
- 📂 遠端檔案管理
- 🔄 檔案同步
🏗️ FTP/SFTP 在網路模型中的位置
OSI 7 層模型
┌──────────────────────────────┬─────────────────┐
│ 7. Application Layer (應用層) │ FTP, SFTP │ ← FTP/SFTP 在這裡
├──────────────────────────────┼─────────────────┤
│ 6. Presentation Layer (表示層)│ 加密、壓縮 │
├──────────────────────────────┼─────────────────┤
│ 5. Session Layer (會話層) │ 建立、維護會話 │
├──────────────────────────────┼─────────────────┤
│ 4. Transport Layer (傳輸層) │ TCP │
├──────────────────────────────┼─────────────────┤
│ 3. Network Layer (網路層) │ IP │
├──────────────────────────────┼─────────────────┤
│ 2. Data Link Layer (資料鏈結層)│ Ethernet │
├──────────────────────────────┼─────────────────┤
│ 1. Physical Layer (實體層) │ 網路線、光纖 │
└──────────────────────────────┴─────────────────┘FTP/SFTP 位於第 7 層(應用層)
- FTP 和 SFTP 都是應用層協定
- 提供檔案傳輸服務
- 支援上傳、下載、刪除等檔案操作
TCP/IP 4 層模型
┌─────────────────────────────┬─────────────────┐
│ 4. Application Layer (應用層) │ FTP, SFTP │ ← FTP/SFTP 在這裡
├─────────────────────────────┼─────────────────┤
│ 3. Transport Layer (傳輸層) │ TCP │
├─────────────────────────────┼─────────────────┤
│ 2. Internet Layer (網際網路層)│ IP │
├─────────────────────────────┼─────────────────┤
│ 1. Network Access (網路存取層)│ Ethernet │
└─────────────────────────────┴─────────────────┘FTP/SFTP 位於第 4 層(應用層)
- 在 TCP/IP 模型中,都是應用層協定
- 使用 TCP 作為傳輸層協定
- TCP 提供可靠的檔案傳輸
檔案傳輸協定對比:
| 協定 | Port | 連線數 | 加密 | 安全性 | 功能 |
|---|---|---|---|---|---|
| FTP | 21 + 20 | 2 個 | ❌ 明文 | ⚠️ 不安全 | 完整檔案管理 |
| FTPS | 990 或 21 | 2 個 | ✅ SSL/TLS | ✅ 安全 | 完整檔案管理 |
| SFTP | 22 | 1 個 | ✅ SSH | ✅ 安全 | 完整檔案管理 |
| SCP | 22 | 1 個 | ✅ SSH | ✅ 安全 | 簡單複製 |
重點:
- FTP 使用 TCP,有兩個連線:
- 控制連線(Port 21):傳送命令
- 數據連線(Port 20 主動 / 隨機 port 被動):傳輸檔案
各協定特色:
FTP(File Transfer Protocol)- 1971 年:
- 明文傳輸(帳號、密碼、檔案內容都可被竊聽)
- 雙連線設計(控制 + 數據)
- 防火牆不友善(主動模式需開 Port 20)
- ⚠️ 不安全,僅建議內網使用
FTPS(FTP over SSL/TLS):
- FTP + SSL/TLS 加密
- Port 990(隱式)或 21(顯式)
- 仍是雙連線
- 比 FTP 安全,但設定較複雜
SFTP(SSH File Transfer Protocol):
- 完全不同於 FTP!基於 SSH
- 加密傳輸(SSH 通道)
- 單一連線(Port 22)
- ✅ 現代標準,推薦使用
- 詳見下一篇:07-2. SFTP 協定
SCP(Secure Copy Protocol):
- 基於 SSH(Port 22)
- 更簡單,只做「複製」
- 不支援續傳、列出目錄
- 詳見:07-3. SCP 協定為什麼 FTP 使用 TCP?
檔案傳輸的需求:
1. 可靠性 ✅
檔案必須完整無誤
TCP 提供錯誤檢測和重傳
2. 順序性 ✅
檔案內容必須按順序到達
TCP 保證封包順序
3. 流量控制 ✅
大檔案傳輸需要流量控制
TCP 提供視窗機制
UDP 不適合:
❌ 不可靠(可能丟包)
❌ 無順序保證
❌ 檔案可能損壞🏗️ FTP 架構
雙連線設計
💡 特色:FTP 使用「兩個」連線客戶端 FTP 伺服器
│ │
├─ 控制連線(Port 21)──────────────>│ 發送命令
│ USER, PASS, LIST, RETR, STOR │
│ │
│<─ 數據連線(Port 20 或動態)────────┤ 傳輸檔案
│ 實際檔案內容 │控制連線(Control Connection):
- Port 21
- 持續保持
- 傳送命令(LIST, GET, PUT)
- 回應狀態碼
數據連線(Data Connection):
- Port 20(主動模式)或動態 Port(被動模式)
- 臨時建立
- 傳輸實際檔案內容
- 傳輸完成後關閉
🔀 主動模式 vs 被動模式
主動模式(Active Mode)
💡 比喻:伺服器主動打電話給你客戶端 (192.168.1.100) FTP 伺服器 (ftp.example.com)
│ │
├─ PORT 192.168.1.100,1234 ────────>│ 告訴伺服器「請連線到我的 1234 port」
│ (控制連線 Port 21) │
│ │
│<─ 200 OK ─────────────────────────┤
│ │
│<─ 數據連線(Port 20 → 1234)───────┤ 伺服器主動連線到客戶端
│ 傳輸檔案 │問題:NAT/防火牆
客戶端(內網) NAT FTP 伺服器
192.168.1.100 ftp.example.com
│ │ │
├─ PORT 命令 ───────>├────────────────>│
│ (告訴伺服器連到 192.168.1.100:1234) │
│ │ │
│ │<─ 嘗試連線 ──────┤
│ │ 到 192.168.1.100:1234
│ │ ❌ 失敗(內網 IP)
│ │ │
│<─ 連線失敗 ─────────┤ │
問題:
1. 伺服器無法連到內網 IP (192.168.1.100)
2. 防火牆阻擋入站連線被動模式(Passive Mode)
💡 比喻:客戶端主動打電話給伺服器
解決 NAT/防火牆問題客戶端 (192.168.1.100) FTP 伺服器 (ftp.example.com)
│ │
├─ PASV ────────────────────────────>│ 請求被動模式
│ (控制連線 Port 21) │
│ │
│<─ 227 (192,168,2,10,200,100) ──────┤ 告訴客戶端「請連線到我的 51300 port」
│ (192.168.2.10:51300) │ (200*256 + 100 = 51300)
│ │
├─ 數據連線(→ 51300)──────────────>│ 客戶端主動連線到伺服器
│ 傳輸檔案 │Port 計算:
227 Entering Passive Mode (192,168,2,10,200,100)
│ │ │ │ │ │
IP位址 Port
IP: 192.168.2.10
Port: 200 * 256 + 100 = 51300解決 NAT 問題:
客戶端(內網) NAT FTP 伺服器
192.168.1.100 203.0.113.5 ftp.example.com
│ │ │
├─ PASV ────────────>├────────────────>│
│ │<─ 227 ───────────┤
│ │ 伺服器 Port: 51300
│ │ │
├─ 連線到 51300 ────>├────────────────>│
│ ✅ 成功(出站連線) │ │🔧 FTP 命令
控制命令
USER <username> - 使用者名稱
PASS <password> - 密碼
PWD - 顯示當前目錄
CWD <directory> - 切換目錄
LIST - 列出檔案
RETR <filename> - 下載檔案
STOR <filename> - 上傳檔案
DELE <filename> - 刪除檔案
MKD <directory> - 建立目錄
RMD <directory> - 刪除目錄
QUIT - 結束連線FTP 會話範例
C: USER alice
S: 331 Password required for alice
C: PASS secret123
S: 230 User alice logged in
C: PWD
S: 257 "/" is current directory
C: LIST
S: 150 Opening data connection
S: -rw-r--r-- 1 alice users 1234 Jan 15 10:00 file.txt
S: drwxr-xr-x 2 alice users 4096 Jan 14 09:00 folder
S: 226 Transfer complete
C: CWD folder
S: 250 CWD command successful
C: RETR document.pdf
S: 150 Opening data connection (12345 bytes)
S: (傳輸 12345 bytes)
S: 226 Transfer complete
C: STOR upload.zip
S: 150 Ready to receive data
C: (傳輸檔案)
S: 226 Transfer complete
C: QUIT
S: 221 Goodbye💻 Python 使用 FTP
基本連線
from ftplib import FTP
# 連線到 FTP 伺服器
ftp = FTP('ftp.example.com')
# 登入
ftp.login(user='alice', passwd='password')
# 顯示歡迎訊息
print(ftp.getwelcome())
# 顯示當前目錄
print(ftp.pwd())
# 列出檔案
ftp.dir() # 詳細列表
# 或
files = ftp.nlst() # 只列出檔案名
for file in files:
print(file)
# 關閉連線
ftp.quit()下載檔案
from ftplib import FTP
ftp = FTP('ftp.example.com')
ftp.login('alice', 'password')
# 下載檔案
filename = 'document.pdf'
with open(filename, 'wb') as local_file:
ftp.retrbinary(f'RETR {filename}', local_file.write)
print(f"{filename} 下載完成")
ftp.quit()上傳檔案
from ftplib import FTP
ftp = FTP('ftp.example.com')
ftp.login('alice', 'password')
# 上傳檔案
filename = 'upload.zip'
with open(filename, 'rb') as local_file:
ftp.storbinary(f'STOR {filename}', local_file)
print(f"{filename} 上傳完成")
ftp.quit()目錄操作
# 切換目錄
ftp.cwd('/public_html')
# 建立目錄
ftp.mkd('new_folder')
# 刪除目錄
ftp.rmd('old_folder')
# 刪除檔案
ftp.delete('file.txt')
# 重新命名
ftp.rename('old_name.txt', 'new_name.txt')被動模式
from ftplib import FTP
ftp = FTP('ftp.example.com')
# 啟用被動模式(預設)
ftp.set_pasv(True)
# 或使用主動模式
# ftp.set_pasv(False)
ftp.login('alice', 'password')
# ... 其他操作斷點續傳
import os
from ftplib import FTP
def resume_download(ftp, remote_file, local_file):
"""斷點續傳下載"""
# 檢查本地檔案大小
if os.path.exists(local_file):
local_size = os.path.getsize(local_file)
else:
local_size = 0
# 從中斷處繼續下載
with open(local_file, 'ab') as f:
ftp.retrbinary(
f'RETR {remote_file}',
f.write,
rest=local_size # 從此位置開始
)
# 使用
ftp = FTP('ftp.example.com')
ftp.login('alice', 'password')
resume_download(ftp, 'large_file.zip', 'local_file.zip')🎓 常見面試題
Q1:FTP 主動模式和被動模式有什麼不同?
答案:
核心差異:「誰」主動建立數據連線?主動模式(Active):
伺服器主動連線到客戶端
客戶端:告訴伺服器「我開了 Port 1234,請連過來」
伺服器:好的,我從 Port 20 連到你的 1234
問題:防火牆/NAT 阻擋入站連線被動模式(Passive):
客戶端主動連線到伺服器
客戶端:請告訴我你的 Port
伺服器:我開了 Port 51300,請連過來
客戶端:好的,我連到你的 51300
優點:解決 NAT/防火牆問題(出站連線)圖解:
主動模式:
Client ─ PORT 1234 ──> Server (Port 21)
Client <─ Data ─────── Server (Port 20 → 1234) ❌ NAT問題
被動模式:
Client ─ PASV ──────> Server (Port 21)
Client <─ 227 (Port) ─ Server
Client ─ Data ──────> Server (Port 51300) ✅ 解決NAT記憶技巧:
- 主動(Active):伺服器像業務員,主動上門(打入站連線)
- 被動(Passive):伺服器像店面,等客人上門(接出站連線)
Q2:如何提升 FTP 傳輸速度?
答案:
1. 使用被動模式:
# 被動模式通常比主動模式快
ftp.set_pasv(True)2. 調整緩衝區大小:
# 增大緩衝區(預設 8192 bytes)
ftp.retrbinary('RETR file.zip', local_file.write, blocksize=262144) # 256 KB3. 平行下載多個檔案:
from concurrent.futures import ThreadPoolExecutor
from ftplib import FTP
def download_file(filename):
ftp = FTP('ftp.example.com')
ftp.login('alice', 'password')
with open(filename, 'wb') as f:
ftp.retrbinary(f'RETR {filename}', f.write)
ftp.quit()
# 平行下載
files = ['file1.zip', 'file2.zip', 'file3.zip']
with ThreadPoolExecutor(max_workers=3) as executor:
executor.map(download_file, files)4. 壓縮後傳輸:
import zipfile
# 壓縮檔案
with zipfile.ZipFile('archive.zip', 'w', zipfile.ZIP_DEFLATED) as zf:
zf.write('large_file1.txt')
zf.write('large_file2.txt')
# 上傳壓縮檔(比傳輸多個小檔案快)
ftp.storbinary('STOR archive.zip', open('archive.zip', 'rb'))5. 使用 SFTP 壓縮選項:
ssh.connect(
hostname='sftp.example.com',
username='alice',
password='password',
compress=True # 啟用 SSH 壓縮
)6. 網路優化:
# Linux 調整 TCP 緩衝區
sudo sysctl -w net.core.rmem_max=16777216
sudo sysctl -w net.core.wmem_max=16777216Q3:如何實作 FTP 斷點續傳?
答案:
原理:
1. 檢查本地檔案大小
2. 告訴伺服器從該位置開始傳輸
3. 追加寫入本地檔案Python 實作:
import os
from ftplib import FTP
def resume_download(ftp, remote_file, local_file):
"""FTP 斷點續傳下載"""
# 檢查本地檔案是否存在
if os.path.exists(local_file):
local_size = os.path.getsize(local_file)
mode = 'ab' # 追加模式
else:
local_size = 0
mode = 'wb' # 新建模式
# 取得遠端檔案大小
remote_size = ftp.size(remote_file)
if local_size == remote_size:
print("檔案已下載完成")
return
print(f"已下載:{local_size} bytes")
print(f"檔案大小:{remote_size} bytes")
print(f"剩餘:{remote_size - local_size} bytes")
# 從中斷處繼續下載
with open(local_file, mode) as f:
ftp.retrbinary(
f'RETR {remote_file}',
f.write,
rest=local_size # 從此位置開始
)
print("下載完成")
# 使用
ftp = FTP('ftp.example.com')
ftp.login('alice', 'password')
# 第一次下載(可能中斷)
try:
resume_download(ftp, 'large_file.zip', 'local.zip')
except KeyboardInterrupt:
print("下載中斷")
# 重新執行,自動續傳
resume_download(ftp, 'large_file.zip', 'local.zip')
ftp.quit()Q4:如何保護 FTP 伺服器?
答案:
1. 限制 IP 存取:
# vsftpd 設定 (/etc/vsftpd.conf)
tcp_wrappers=YES
# /etc/hosts.allow
vsftpd: 192.168.1.0/24
# /etc/hosts.deny
vsftpd: ALL2. 使用 chroot 限制目錄:
# vsftpd 設定
chroot_local_user=YES # 限制使用者在家目錄3. 限制頻寬:
# vsftpd 設定
local_max_rate=1000000 # 1 MB/s
anon_max_rate=500000 # 500 KB/s4. 記錄日誌:
# vsftpd 設定
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log
# 監控異常活動
tail -f /var/log/vsftpd.log5. 使用 Fail2Ban 防止暴力破解:
# /etc/fail2ban/jail.local
[vsftpd]
enabled = true
port = ftp,ftp-data,ftps,ftps-data
logpath = /var/log/vsftpd.log
maxretry = 3
bantime = 3600 # 封鎖 1 小時6. 定期更新與稽核:
# 檢查 FTP 版本
vsftpd -v
# 更新
sudo apt-get update
sudo apt-get upgrade vsftpd
# 檢查登入記錄
sudo grep "FAIL LOGIN" /var/log/vsftpd.log📝 總結
FTP 協定核心要點:
雙連線設計 📁
- 控制連線(Port 21):傳送命令
- 數據連線(Port 20/動態):傳輸檔案
兩種模式 🔀
- 主動模式:伺服器主動連線(有 NAT 問題)
- 被動模式:客戶端主動連線(推薦)
安全性問題 ⚠️
- 明文傳輸(密碼、檔案內容可被竊聽)
- 建議:內網使用或改用 SFTP
記憶口訣:「雙控數,主被動」
- 雙:雙連線(控制+數據)
- 控數:控制連線(21)+ 數據連線(20)
- 主被動:主動模式 vs 被動模式
使用建議:
✅ 適合場景:
- 內網環境(安全性要求低)
- 速度優先(無加密開銷)
- 舊系統相容性需求
⚠️ 不適合場景:
- 公網環境(建議用 SFTP)
- 傳輸敏感資料(建議用 SFTP)
- 需要強認證(建議用 SFTP)🔗 延伸閱讀
- 下一篇:07-2. SFTP 協定
- 相關文章:07-3. SCP 協定
- RFC 959(FTP):https://tools.ietf.org/html/rfc959
- vsftpd 官方文件:https://security.appspot.com/vsftpd.html