FTPはファイルの転送に使用されるプロトコルの一つです。
普段FTPクライアントが行っているファイル転送の処理を、telnetを使用して自分で確認してみましょう――と言いたいところですが、実は今まで紹介してきた通りのやり方では、telnetでFTPを使ったファイル転送はできません。とは言え、それが不可能というわけではありません。しかし、プロトコル自体も(telnetを除いて)今まで紹介してきたものよりも複雑ですし、FTPを使える環境にある人はメールのそれ程には多くないと思います。以上の理由から、この章は一応中級者以上向けとさせて頂きます。
FTPでは、"コントロールコネクション"と"データコネクション"という、二種類のコネクションが使用されます。コントロールコネクションでは、サーバーとユーザーとの間で交わされるコマンドとその応答がやり取りされ、データコネクションではファイルやそのリスト一覧等のデータがやり取りされます。
FTPの作業を開始するということはコントロールコネクションを開始するということであり、このコネクションはユーザーによって明示的に終了を指示されるまで続きます。これに対してデータコネクションは転送要求コマンドによって確立され、その接続と終了は基本的にサーバーによって管理されます。このコネクションは常に存在するわけではありません。
このように二重のコネクションを使用することで、データ転送中でもコマンドを発行することができ、転送制御が容易になります。
先程"今までのやり方ではtelnetでFTPの機能は利用できない"と述べたのは、実はこのことが原因です。telnetは複数のコネクションを同時に扱えないからです。他にもデーターコネクション用のサーバー機能がないというのも原因の一つなのですが、これについては後述します。
データコネクション張る際、デフォルトではコントロールコネクションの相手(つまりはユーザー)に、サーバー側から接続します。これはアクティブモードと呼ばれ、ユーザーはサーバーが接続してくるポートをlistenしておく必要があります(telnetではそんなことはできません)。
しかしユーザーがファイアウォールの内側にいる場合、これに外部から接続することは通常許可されていません。そうした問題を解決する方法に、パッシブモードというものがあります。これはアクティブモードとは接続方向が逆になります。
ただし、上記はデータコネクションの接続方向に関することであり、データコネクションを使用したデータの転送自体は、双方向で可能であるということを断っておきます。
ちなみにサーバーがデータコネクションを張る相手は、コントロールコネクションの相手である必要はありません。これについては[FTPでサーバー間転送を行う]を参照して下さい。
基本的な設定としては、「ローカルエコー」オン、「漢字コード」日本語EUC、「エミュレーション」VT-100/漢字です。エンターキーを押下したときに送信するコードを変更できるクライアントをお使いの場合は、CRLFを送るようにしておきます。設定の仕方は[クライアントの設定・基本操作]を参照して下さい。
設定が済んだら接続してみましょう。「接続」の「リモートシステム」を選択して下さい。標準ではFTPの(コントロールコネクションの)ポート番号は21なので、それを使用します。
ここではNURSのFTPサーバーに接続してみます。
NURSの場合、正しく接続できたら次のように表示されます。
220 ProFTPD 1.2.5rc1 Server (Debian) [jh4tjwgw.nurs.or.jp]
このように表示されない場合は接続に失敗している可能性があります。ホスト名、ポート番号を確認して再度接続し直して下さい。
FTPのコマンドのうち、主なものを挙げておきます。斜体の部分は引数、[]の中の引数は省略可能です。
コマンドとその構文 | 意味 |
---|---|
USER username | ユーザー名を知らせます。認証に必要です。 |
PASS password | パスワードを知らせます(平文)。認証に必要です。 |
CWD pathname | 指定したディレクトリを作業ディレクトリにします |
CDUP | 親ディレクトリを作業ディレクトリにします。 |
QUIT | ログアウトしてコントロールコネクションを切断します。 |
PORT IP-address & portnumber | データコネクションで使用するホストとポートを指定します。 |
PASV | パッシブモードへの移行を指示します。データコネクションで使用するホストとポートが応答で示されます。 |
TYPE [data-type [format/bytesize]] | data-typeで転送データの形式を指定します。第二引数で書式、もしくはバイト長を指定します。data-typeはA/E/I/L、formatはN/T/Cのいずれかが指定できます。省略時のデフォルトはA Nです。 |
RETR pathname | 指定したファイルをサーバーから送信します。 |
STOR pathname | サーバーへ送信するデータを指定したファイル名で保存します。同一のパスで示されるファイルが既に存在する場合、上書きされます。 |
STOU | STORと同様の動作をしますが、作成されるファイルには自動的に重複しない名前が付けられます。 |
APPE pathname | サーバーへ送信するデータを指定したファイルに追加します。指定したファイルが存在しない場合は、新規に作成されます。 |
RNFR pathname | 名前を変更するファイルを指定します。続けてRNTOコマンドを実行する必要があります。 |
RNTO pathname | 直前のRNFRコマンドで指定されたファイルの名前を、指定したファイル名に変更します。 |
ABOR | 実行中のデータ転送を中止し、データコネクションを切断します。 |
DELE pathname | 指定したファイルを削除します。 |
RMD directory | 指定したディレクトリを削除します。 |
MKD directory | 指定した名前のディレクトリを作成します。 |
PWD | 現在の作業ディレクトリを表示します。 |
LIST [pathname] | 指定したパス名がファイルの場合は属性などを含めたそのファイルの情報を、ディレクトリの場合はそのディレクトリ内のファイル一覧を送信します。引数がないと、現在の作業ディレクトリまたはデフォルトのディレクトリが指定されたものとみなされます。 |
NLST [pathname] | 指定したパス名のディレクトリ内のファイルの名前一覧を送信します。引数がないと、現在の作業ディレクトリが指定されたものとみなされます。 |
SITE command | 任意のサーバーOSのコマンドを実行します。 |
STAT [pathname] | システム、転送の状態をコントロールコネクションを使用して返します。ファイル転送中にこのコマンドが実行されると転送の処理状態を、それ以外に実行されるとFTPプロセスの一般的な情報を返します。 引数としてパス名が与えられると、その情報を返します(NLST/LISTと同等)。 |
HELP [command] | サーバーの実装状況(使用可能なコマンドの一覧等)を返します。引数を指定すると、それに関するより詳しい情報を返します。 |
NOOP | 何もしません。タイムアウトにならないよう接続を維持しておきたい時や、接続、サーバーの動作の確認などに使います。 |
パス名には相対パス、絶対パスのどちらも含まれます。
PORT/PASVコマンドにおけるホストとポートのフォーマットは、32ビットのIPアドレスと16ビットのポート番号を結合し、8ビット毎にカンマで区切ったもので、h1,h2,h3,h4,p1,p2のようになります。h1はIPアドレスの最上位8ビットで、各8ビットはそれぞれ十進数で表記されます。例えば192,168,1,10,23,112なら、IPアドレス192.168.1.89、ポート番号6000(=256*23+112)となります。
PORT/PASVコマンドはいずれも、デフォルト以外のポートをデータコネクションで使用するためのコマンドです。しかしデータコネクションで使用されるポートは、ユーザー側にもサーバー側にもデフォルトポートが存在します。ですからPORTコマンドは使用する必要はありません。
ただし、詳しい説明はしませんが、FTPには転送モードというものが存在します。それにはいくつか種類があるのですが、デフォルトであるストリームモード以外はほとんど使われません。このストリームモードでは、EOF(ファイルの終わり)はデータコネクションの終了で示されます。つまり複数のファイルを送ろうと思えば、その数だけデータコネクションを確立し直す必要があるということです。
ところがTCPはコネクションが切断されてもすぐにはCLOSE状態にはならず、TIME_WAIT状態がしばらく続きます。この間はコネクションの再確立ができませんから、複数のファイルを送ろうと思うと無駄な時間がかかってしまいます。しかしこれを、PORTコマンドを使ってデフォルト以外のポートを使用することで回避できます(その際ユーザー側のデータポートを固定にするなどという無意味なことはしないように)。
TYPEコマンドの引数のA、E、Iは、それぞれASCII、EBCDIC、IMAGEを表します。
ASCIIはコードをNVT-ASCIIと呼ばれる共通体系に変換して送信するものです。送信側がデータをそのOSの内部表現形式から標準形式へ変換して送信し、受信側はそれを自身の内部形式に再変換することで、テキストデータ中の改行コードの違いなどの問題をクリアできるのです。
EBCDICはIBMが策定したEBCDICという文字コードを使用して送受信するものです。文字コードが違うこと以外はASCIIと同じです。汎用大型コンピュータなどで利用されており、両方がこの文字コードを使用している場合以外は、まず使うことはないはずです。
IMAGEはデータを変換せずに送受信します。バイナリデータの転送に使用されます。
その他の引数はほとんど使われることはありません。これらの引数を使用するような方は、このサイトで説明している程度のことを理解するだけでは不十分だと思いますので、FTPについて専門的に解説した文書を読むことをお勧めします。
NLSTコマンドはファイル名の一覧を返すだけです。これはLISTコマンドの返す情報がOSに依存した情報を返すため、その情報をプログラムで自動的に処理するのには向いていないからです。ただし、RFC 959ではなんら規定はされていませんが、多くの場合NLSTはUNIXのlsコマンドの引数を取ることができるようです。その場合、NLST -alとすることで、LISTコマンドと同じ結果が得られます。
SITEコマンドはサーバーOSのコマンドを実行できるコマンドです。例えばUNIX系OSのサーバーでファイルのパーミッションを変更したい場合は、
SITE chmod 755 test.cgi
のようになります。ただし全てのコマンドが使えるとは限りません。HELP SITEで確認するとよいです。
FTPについてもっと詳しく知りたいと言う方はRFC 959をご覧になって下さい。
では実際にはどの様になるのか、流れを示したいと思います。
まず接続します。DOSプロンプト等から[クライアントの設定・基本操作]で示した手順でtelnetを起動させ、接続して下さい。接続に成功したら、USERコマンドとPASSコマンドを使用して認証を行います。
220 ProFTPD 1.2.5rc1 Server (Debian) [jh4tjwgw.nurs.or.jp]
USER telnet
331 Password required for telnet.
PASS hogehoge
230 User telnet logged in.
PWD
257 "/home/telnet" is current directory.
CWD public_html
250 CWD command successful.
PWD
257 "/home/telnet/public_html" is current directory.
上ではログイン後に/home/telnet/public_htmlディレクトリに移動しています。
PASV
227 Entering Passive Mode (210,251,121,130,16,72).
PASVコマンドでサーバーをパッシブモードにします。この応答で得たIPアドレスとポート番号の情報を元に、データコネクションを確立します。
今使用しているのとは別にtelnetをもう一つ起動させ、ホスト:210.251.121.130、ポート4168(=256*16+72)に接続して下さい。接続できても何も表示されませんが、telnetのタイトルバーに接続先が表示されたら、コネクションが張れたということです。
これでデータコネクションがユーザーとサーバー間で張られたので、まずはファイル一覧を取得してみましょう。なおここから先、ファイル構造は全てデフォルトのファイルであるものとします。
今までコマンドを打ってきた方の――つまり最初に起動させた方のtelnetから、LIST(あるいはNLSTでも構いません。お好みに合わせて)コマンドを発行します。
LIST
150 Opening ASCII mode data connection for file list
226-Transfer complete.
226 Quotas off
すると後から起動させたtelnetに下のようなファイル一覧(NLSTに-lオプションをつけていない場合はただのファイル名の羅列になります)が表示されて、接続が切れたと思います。
言い忘れていましたが、ファイル一覧の取得時はログを取っておいた方が良いと思います。ログはデータコネクションごとに別のファイルに保存した方が都合がいいでしょう。ログのとり方については、[クライアントの設定・基本操作]を参照して下さい。
-rw-r--r-- 1 telnet users 7772 Mar 4 12:04 about.html
-rw-r--r-- 1 telnet users 2114 Mar 4 12:04 analysis.js
drwx-----x 2 telnet users 4096 Mar 4 12:09 cgi-bin
-rw-r--r-- 1 telnet users 4166 Mar 4 12:04 default.css
-rw-r--r-- 1 telnet users 11180 Mar 4 12:04 http.html
drwxr-xr-x 2 telnet users 4096 Mar 4 12:05 img
-rw-r--r-- 1 telnet users 4480 Mar 4 12:07 ip.pl.txt
-rw-r--r-- 1 telnet users 13645 Mar 4 12:04 telnet.html
-rw-r--r-- 1 telnet users 326 Mar 4 12:04 tips.css
-rw-r--r-- 1 telnet users 18107 Mar 5 07:10 tips.html
次はファイルをダウンロードしてみましょうか。例によってパッシブモードにした後、もう一つのtelnetでデータコネクションを再確立し、RETRコマンドでip.pl.txtを取得します。先程とはポートが異なることに注意して下さい。
PASV
227 Entering Passive Mode (210,251,121,130,16,82).
RETR ip.pl.txt
150 Opening ASCII mode data connection for ip.pl.txt (4480 bytes).
226 Transfer complete.
今度はファイルをアップロードしてみます。三度パッシブモードにし、データコネクションを確立。そしてデータ送受信用のtelnetの画面にコピーアンドペーストで適当なテキストを貼り付けます。そしてSTORコマンドでtest.txtという名前でサーバー上へのデータの書き込みを指示。ストリームモードですから、EOFはコネクションの終了で示されます。よって、転送するのに十分な時間が経過したと思ったら、データコネクションを切断して下さい。これで転送完了です。
PASV
227 Entering Passive Mode (210,251,121,130,16,91).
STOR test.txt
150 Opening ASCII mode data connection for test.html
226 Transfer complete.
本当に書き込めているかどうかを確認するのには、普通はLISTやNLSTコマンドを使うのかもしれませんが、ファイル一覧のためだけにデータコネクションをいちいち張り直したりするのは面倒です。
STATコマンドに引数としてパス名を与えると、そのパスのファイル(ディレクトリ)の情報を応答として返します。応答はコントロールコネクションを使用してユーザーに渡されますから、データコネクションを張る必要はありません。よってSTATコマンドを使用してファイル一覧を取得することにします。
STAT /home/telnet/public_html
211-status of /home/telnet/public_html:
211-drwx---r-x 4 telnet users 4096 Mar 25 13:43 .
211-drwx-----x 3 telnet users 4096 Mar 4 12:36 ..
211--rw-r--r-- 1 telnet users 7772 Mar 4 12:04 about.html
211--rw-r--r-- 1 telnet users 2114 Mar 4 12:04 analysis.js
211-drwx-----x 2 telnet users 4096 Mar 4 12:09 cgi-bin
211--rw-r--r-- 1 telnet users 4166 Mar 4 12:04 default.css
211--rw-r--r-- 1 telnet users 11180 Mar 4 12:04 http.html
211-drwxr-xr-x 2 telnet users 4096 Mar 4 12:05 img
211--rw-r--r-- 1 telnet users 4480 Mar 4 12:07 ip.pl.txt
211--rw-r--r-- 1 telnet users 13645 Mar 4 12:04 telnet.html
211--rw-r--r-- 1 telnet users 1166 Mar 25 13:42 test.txt
211--rw-r--r-- 1 telnet users 326 Mar 4 12:04 tips.css
211--rw-r--r-- 1 telnet users 18107 Mar 5 07:10 tips.html
211 End of Status
確かにtest.txt(1166 bytes)が書き込まれているのが判ります。
最後にtest.txtを削除してログアウトします。
DELE test.txt
250 DELE command successful.
QUIT
221 Goodbye.
220 ProFTPD 1.2.5rc1 Server (Debian) [jh4tjwgw.nurs.or.jp]
二重のコネクションを使うFTPの複雑さの一端を垣間見ることができたでしょうか。
普段使っているGUIあるいはCUIのFTPクライアントは、複数のファイルを一度にアップ/ダウンロードしているように見えますが、実は単にSTORやRETRコマンドを複数回実行しているに過ぎません。
また、CUIのFTPクライアントなどで使われているlsやgetのようなコマンドは、上記のコマンド表を見ても判るようにFTPのコマンドではなく、クライアントがそれらのローカルなコマンドをFTPのコマンドへと変換しているわけです。ちなみにサーバーでは逆のことが行われています。
このような処理を行う部分をPI(Protocol Interpreter)と呼び、サーバー側をサーバーPI、ユーザー側をユーザーPIと呼びます。
ファイルシステムにアクセスし、データコネクションを確立・管理する部分はDTP(Data Transfer Process)と呼ばれ、これもサーバーDTP、ユーザーDTPの両方が存在します。
これらのことも頭に留めておいて下さい。