FTP クライアントを作ってみよう (4)

前へ << FTP クライアントを作ってみよう (3) FTP クライアントを作ってみよう (5) >> 次へ

FTP プロトコルの仕様

FTP の主要なコマンドを、以下に示します。
ここでいう FTP コマンドとは、get・put・binary・ls・cd などの /usr/bin/ftp や FTP.EXE が受け付けるコマンドでなく、 FTP クライアントが実際に送信する FTP プロトコルのことです。 お間違えなく。

これらのコマンドは、全てコマンドコネクションを通じて、 FTP クライアントが FTP サーバに送るものです。 データコネクション上をコマンドが送信されることはありませんし、 FTP サーバから FTP クライアントにコマンドが送信されることはありません。

FTP には、OS と同じくカレントディレクトリという概念があり、 ファイル・ディレクトリの指定には相対パスを使うことができます。 CWD・RETR・STOR・LIST・NLIST・MKD・RMD・RNFR・RNTO・MDTM など、 ファイル名やディレクトリ名を引数として受けるものは、

CWD /home/username/public_html
RETR /tmp/file
などと、絶対パスで表記してもよいですし、
LIST dir/subdir
LIST .
MKD ../newdir
と、相対パスを使うこともできます。「.」や「..」を、 「カレントディレクトリ」、「一つ上のディレクトリ」という意味で使えます。

ここで説明する仕様は、現在の多くの FTP サーバでは使用可能だと思われますが、 正式なものではありません。例えば 「CWD コマンドの引数を省略するとホームディレクトリに移動する」は、 RFC では保証されていません。


ユーザ認証
    FTP サーバに接続後、ユーザ認証を行わなければならない。USER・PASS コマンドで、 ユーザ名とパスワードを送信する。

  • USER … ユーザ名を送信
  • PASS … パスワードを送信
    USER username
    331 Password required for username.
    PASS password
    230 User username logged in.
    

ファイル・ディレクトリ操作
  • MKD … 新しいディレクトリを作成
    MKD dirname で、新しいディレクトリ dirname を作成する。
  • RMD … ディレクトリを削除
    RMD dirname で、ディレクトリ dirname を削除する。
  • RNFR … ファイル名を変更 (存在するファイル名を送信)
  • RNTO … ファイル名を変更 (新しいファイル名を送信)
    ファイル a の名前を b に変更したいときは、
    RNFR a
    350 File exists, ready for destination name
    RNTO b
    250 RNTO command successful.
    
    とする。
  • MDTM … ファイルの最終更新時刻を取得
    引数で指定したファイルの最終更新時刻を取得する。ファイルを RETR したとき、 ファイルの最終更新時刻を、サーバでの最終更新時刻に合わせるときや、 指定したファイルが、サーバ側のファイルより新しいかどうかを調べるときなどに使う。
    MDTM filename
    213 19990522151430
    
    この例では、ファイル filename の最終更新時刻を取得している。 19990522151430 というのは「1999年5月22日15時14分30秒」ということだが、 GMT 表記であることに注意。JST だと +9 時間 なので、「1999年5月23日0時14分30秒」を意味する。
  • SIZE … ファイルのサイズを取得

ディレクトリ
  • PWD … 現在のカレントディレクトリを取得
    現在のカレントディレクトリを表示する。
    PWD
    257 "/usr/home/username/public_html" is current directory.
    
  • CWD … 現在のカレントディレクトリを変更
    CWD dirname で、カレントディレクトリを dirname に移動する。 引数なしで CWD コマンドを送信したときは、ホームディレクトリに移動する。
    CWD /var/
    250 CWD command successful.
    PWD
    257 "/var" is current directory.
    CWD /var/log
    250 CWD command successful.
    PWD
    257 "/var/log" is current directory.
    CWD ..
    250 CWD command successful.
    PWD
    257 "/var" is current directory.
    CWD
    250 CWD command successful.
    PWD
    257 "/usr/home/username" is current directory.
    

データ転送
    これらのコマンドを実行すると、データコネクションを通じてデータが送信される。 そのため、事前に PORT コマンドか PASV コマンドを実行しておかなくてはいけない。

  • LIST … ファイル一覧を取得 (ls)
    ファイル・ディレクトリの一覧を取得する。ls コマンドと同様に、 引数にファイル名・ディレクトリ名を与えることができる。 引数を省略すると、カレントディレクトリにある、全ファイル・ディレクトリの一覧を取得する。 どのような形式でファイル名が送られてくるかは処理系依存である。 サーバの OS が UNIX だと、ls -l の出力がそのまま送られる。
  • NLST … ファイル一覧の短縮形を取得
    LIST コマンドで得られる一覧の形式は処理系依存だが、NLST はファイル名のみを送信する。 ファイルのパーミッション、オーナー、サイズ、タイムスタンプなどの情報は付属しない。 1 行につき 1 つのファイル (またはディレクトリ) が送られる。
  • RETR … ファイルを取得 (get)
    FTP サーバ側のファイルを FTP クライアントに転送する。ファイル名は引数で指定する。 RETR コマンドを送信した後、FTP クライアントはデータコネクションから 指定したファイルを取得する。
  • STOR … ファイルを送信 (put)
    FTP クライアント側のファイルを FTP サーバに転送する。 FTP サーバに置くファイルの名前を引数で指定しなければならない。 STOR コマンドを送信した後、FTP クライアントはデータコネクションを通じて ファイルの内容を送信しなければならない。

ポート番号の伝達
  • PORT … ポート番号を送信 (Active モード)
    データコネクションの確立の際、FTP サーバ側から FTP クライアント側に接続するよう伝える。 FTP クライアントが IP アドレス 10.0.0.1 で動いており、ポート 5000 番を listen しているなら、
    PORT 10,0,0,1,19,136
    200 PORT command successful.
    
    と送信する (5000=19×256+136)。 その後 FTP クライアントが LIST やRETR コマンドを送信すると、 FTP サーバ側が 10.0.0.1 のポート 5000 に接続し、データの送受信が始まる。
  • PASV … ポート番号を受信 (Passive モード)
    データコネクションの確立の際、FTP クライアント側から FTP サーバ側に接続することを伝える。 PASV コマンドを送信すると、
    PASV
    227 Entering Passive Mode (10,0,0,1,156,115)
    
    と、IP アドレスとポート番号が送られてくる。 その後 FTP クライアントが LIST やRETR コマンドを送信し、 PASV のレスポンスで示された IP アドレス (10.0.0.1) + ポート番号 (40051=156×256+115) に接続すると、データの送受信が始まる。

その他
  • SITE … 特別なコマンドを送信 (chmod・umask・idle など)
    ftp コマンドは chmod・umask などでパーミッションを操作できるが、FTP プロトコルには そのためのコマンドは用意されていない。そのような用途には SITE コマンドを使う。 ファイル・ディレクトリのパーミッションを変更するには、SITE CHMOD を使う。
    SITE CHMOD 755 filename
    200 CHMOD command successful.
    
    この例は、ファイル filename のパーミッションを 755 に変更している。

    新しく作成するファイルのパーミッションを決める際には、umask という値が関わってくる。 現在の umask の値を参照するには、引数を渡さず SITE UMASK とする。

    SITE UMASK
    200 Current UMASK is 022
    
    umask の値を変更するには、SITE UMASK の後に設定したい umask の値を渡す。
    SITE UMASK 002
    200 UMASK set to 002 (was 022)
    
    詳しくは UNIX コマンドリファレンス: umask を参照してほしい。

    SITE コマンドでどのような操作が可能かは、HELP SITE で知ることができる。 SITE CHMOD に対応していない FTP サーバもある。

  • REST … リスタート位置を設定
    ファイルを途中までダウンロードしたが、コネクションが切断された場合には、 ファイルを途中から転送し直すことができる。例えばファイルを 23456 バイトまで 転送したところでコネクションが切断された場合は、
    REST 23456
    350 Restarting at 23456. Send STORE or RETRIEVE to initiate transfer.
    
    とした後に RETR コマンドを使うと、ファイルの 23457 バイト目から転送が開始される。
  • SYST … OS の種類を取得
  • TYPE … ファイルの種類を伝える
    ASCII モードなら TYPE A、BINARY モードなら TYPE I とする。
  • HELP … ヘルプを表示
    HELP コマンドを送信すると、使用可能なコマンドの一覧が送信されてくる。 HELP SITE などと、特定のコマンドの使用方法を知ることもできる。 HELP SITE CHMOD とすることも可能である。

レスポンス

FTP クライアントが FTP サーバにコマンドを送信すると、 必ず FTP サーバは以下のようなレスポンスを返します。
220 Hostname FTP server (Version 6.00) ready.
226 Transfer complete.
227 Entering Passive Mode (10,0,0,1,156,92)
331 Password required for username.
500 'hoge': command not understood.
レスポンスの先頭にはレスポンスコードと呼ばれる 3 桁の数字が書かれており、 この数字によって、処理が成功したか失敗したかなどを FTP クライアントが 知ることができします。

複数行のレスポンスが渡される可能性もあります。 その場合は

xyz-.....
...
...
xyz ....
という風に、最初に
xyz(レスポンスコード)-(ハイフン) 
で始まり、
xyz(レスポンスコード) (スペース) 
で終わる、という構造になります。例えば、 anonymous ftp ftp://ftp.jp.FreeBSD.org にログインすると、
230-    Welcome to FTP.JPIX.ad.jp.        ########## ######### ###
230-    Located in Tokyo, Japan.            #  #   ##  #   ##   #
(中略)
230-    Please send E-mail to amaike@iri.co.jp if you have any questions
230-    or problems.  thanks!
230-
230 User ftp logged in.  Access restrictions apply.
となります。この例では途中の行も「230-」から始まっていますが、 FTP プロトコルとしては、途中の行はどのような文字から始めても構いません。

レスポンスコード

FTP サーバが返すレスポンスコードは必ず 3 桁の数字になっています。 最初の数字を見ることで、エラーかどうかを判断することができます。
  • 1yz 肯定的な事前レスポンス
    150 Opening ASCII mode data connection for '/bin/ls'.

  • 2yx 肯定的な完了レスポンス
    処理が成功したことを示します。FTP サーバに接続すると、
    220 Hostname FTP server (Version 6.00) ready.
    
    というレスポンスが返されます。USER・PASS コマンドで認証に成功すると、
    230 User Username logged in.
    
    となります。その他、PWD・CWD・PORT・PASV・LIST・RETR・STOR など、 そのコマンドが成功すると、
    257 "/usr/home/zxr400" is current directory.
    200 PORT command successful.
    227 Entering Passive Mode (127,0,0,1,156,102)
    226 Transfer complete.
    
    です。

  • 3yz 肯定的な中間レスポンス
    コマンドは受け入れらましたが、その後に別のコマンドを送信しなければいけません。 例えば、USER コマンドを送ると
    USER username
    331 Password required for username.
    
    というレスポンスが返ってきます。この後に PASS コマンドを送らなければいけません。 また、ファイル名を a から b に変更しようと RNFR コマンドを送信すると、
    RNFR a
    350 File exists, ready for destination name
    
    となります。この後、RNTO で変更したいファイル名を送らないといけません。

  • 4yz 一時的かつ否定的な完了レスポンス (エラー)
    一時的なエラーを表します。例えば、PORT コマンドや PASV コマンドを送信せずに LIST・RETR・STOR コマンドを使うと、データコネクションの準備ができていないので、
    425 Can't build data connection: Connection refused.
    
    となります。また、長時間入力がなかった場合、タイムアウトになりますが、そのとき
    421 Timeout (30 seconds): closing control connection.
    
    となります。

  • 5yz 否定的なレスポンス (エラー)
    エラーです。 USER・PASS コマンドでユーザ認証に失敗すると、
    530 Login incorrect.
    
    となります。パーミッション的に移動できないディレクトリに CWD しようとすると、
    550 dir: Permission denied.
    
    となります。その他、存在しないファイルや読めないファイルを RETR しようとしたり、定義されていないコマンドを送信すると
    500 'HOGE': command not understood.
    
    などとなります。
前へ << FTP クライアントを作ってみよう (3) FTP クライアントを作ってみよう (5) >> 次へ

ご意見・ご指摘は Twitter: @68user までお願いします。