ホーム › ネットワーク › N-08: FTP ファイル転送
N-08: FTP ファイル転送(FTPClient ソケット実装)
FTP(File Transfer Protocol)は、ファイルをサーバーにアップロード・ダウンロードするためのプロトコルです。 このページでは FTP プロトコルの仕組みを TCP ソケットで実装しながら理解します。 コマンドチャネル(制御用)とデータチャネル(転送用)の 2 本の接続を使う点が特徴です。
⚠️ このページは「仕組みを理解する」ための実装です
実務で FTP を使う場合は Apache Commons Net の FTPClient クラスを使用してください。 ソケットで手作りすると、タイムアウト処理・SSL/TLS(FTPS)対応・ マルチライン応答の処理など多くの考慮事項があります。
FTP プロトコルの仕組み
FTP は 2 本のコネクションを使います。 「コマンドチャネル(ポート 21)」でコマンドを送受信し、 「データチャネル(PASV で動的に決まるポート)」でファイルを転送します。 この 2 チャネル構成が FTP の最大の特徴です。
| チャネル | ポート | 用途 |
|---|---|---|
| コマンドチャネル | 21(固定) | コマンド送信・応答受信(接続中ずっと維持) |
| データチャネル | PASV で動的決定 | ファイルの実際の転送(転送ごとに開いて閉じる) |
PASV ポート計算式
// サーバーから受信する応答例
227 Entering Passive Mode (192,168,1,1,196,10)
// カッコ内の最後の2数字を使う
データチャネルポート = 196 × 256 + 10 = 50186
サンプルコード
Java 8 版では FTP プロトコルのフローと主要コマンドを説明し、PASV ポート計算を実装しています。 Java 17 版では record で FTP コマンドを型安全に表現し、switch 式で応答コードを分類します。 Java 21 版では sealed interface と パターンマッチング switch で FTP 応答カテゴリを型安全に処理します。
よくあるミス・注意点
⚠️ アクティブモードとパッシブモードの混同
FTP にはアクティブモード(PORT コマンド)とパッシブモード(PASV コマンド)があります。 アクティブモードはサーバーがクライアントに接続するため、 クライアント側のファイアウォールで接続が遮断されることがあります。 ファイアウォール環境では必ずパッシブモード(PASV)を使用してください。
// アクティブモード(NG: ファイアウォールで遮断されやすい) // C: PORT 192,168,1,100,200,50 ← クライアントが待ち受けポートを指定 // S: サーバーからクライアントに接続してくる // パッシブモード(OK: ファイアウォールに優しい) // C: PASV // S: 227 Entering Passive Mode (192,168,1,1,196,10) // C: クライアントがサーバーのデータポートに接続する
バイナリモードとテキストモードの違い
FTP のデフォルト転送モードはテキストモード(TYPE A)です。 テキストモードでは改行コードが OS に合わせて変換されるため、 バイナリファイル(画像・PDF・ZIP など)が破損します。 ファイル転送前に必ず TYPE I でバイナリモードに切り替えてください。
// バイナリファイル転送前に必ず設定 C: TYPE I S: 200 Type set to I (Binary mode) // テキストファイルの場合(改行変換が必要な場合のみ) C: TYPE A S: 200 Type set to A (ASCII mode)
Java バージョンごとの違い
Java 8 ではすべてクラスと通常の変数宣言で実装します。 Java 17 では record で コマンドを不変なデータとして表現でき、switch 式で応答コードを簡潔に分類できます。 Java 21 では sealed interface と パターンマッチング switch を組み合わせることで、応答カテゴリの網羅的な処理が コンパイル時に保証されます。
テストする観点
- PASV レスポンスのポート計算が正しいか (例:
196,10→196×256+10=50186) - PASV レスポンスの形式が不正な場合に
IllegalArgumentExceptionが発生するか - 応答コードの分類(1xx/2xx/3xx/4xx/5xx)が正しいか (境界値: 100・199・200・299・300・399・400・499・500・599)
- FTP コマンド文字列が CRLF(
\\r\\n)で終端されているか - 引数なしコマンド(PASV・QUIT など)と引数ありコマンド(USER・STOR など)でコマンド行の形式が正しいか