JavaによるFTPサーバの実装
詳細
【概要】
FTP(File Transfer Protocolファイル転送プロトコル)は、インターネット上でファイルを転送するためのプロトコルです.インターネット上ではFTPサーバを介してファイルのアップロード(Upload)やダウンロード(Download)が可能です.FTPはリアルタイムオンラインサービスであり、それを使用する前にそのサービスを持つユーザー(ユーザー名とパスワード)でなければならない.作業時にクライアントはサーバー側のコンピュータにログインしなければならない.ユーザーがログインした後、ファイル検索とファイル転送などの操作を行うことができる.例えば、現在の作業ディレクトリ、列ファイルディレクトリの変更、転送パラメータの設定、ファイル転送などである.FTPを使用すると、テキストファイル、バイナリ実行ファイル、イメージファイル、サウンドファイル、データ圧縮ファイルなど、すべてのタイプのファイルを転送できます.
FTPコマンド
FTPの主な動作は,様々な命令に基づいている.一般的なコマンドは次のとおりです.
◆ASCII(テキスト)とBINARYバイナリモードを含む転送モードを設定する.
◆ディレクトリ操作、リモートコンピュータの現在のディレクトリ(cd、dir/lsコマンド)を変更または表示する.
◆接続操作、openコマンドはリモートコンピュータとの接続を確立するために使用される.closeコマンドは接続を閉じるために使用されます.
◆ファイルをリモートコンピュータに転送するためにputコマンドを送信する操作.mputコマンドは、複数のファイルをリモートコンピュータに転送するために使用されます.
◆取得操作、getコマンドはファイルを受信するために使用される.mgetコマンドは、複数のファイルを受信するために使用されます.
プログラミング構想
FTPの動作原理に基づいて、主関数の中で1つのサーバーソケットポートを創立して、クライアントの要求を待って、いったんクライアントの要求が受け入れられると、サーバーのプログラムは1つのサーバーのスレッドを創立して、クライアントの命令を処理します.クライアントがサーバ側とファイルの転送を行う必要がある場合は、ファイルの操作を完了するために新しいソケット接続を確立します.
プログラミングテクニックの説明
1.主関数設計
メイン関数では、サーバポートのリスニングとサービススレッドの作成を完了します.静的文字列変数initDirを使用して、サーバスレッドの実行時に存在する作業ディレクトリを保存します.サーバーの初期作業ディレクトリは、プログラム実行時にユーザーが入力したもので、デフォルトはCディスクのルートディレクトリです.
具体的なコードは以下の通りです.
2.スレッドクラスの設計
スレッドクラスの主な設計はrun()メソッドで実現される.run()法でクライアントのソケット情報を得,ソケットに基づいて入力ストリームと出力ストリームを得,クライアントに歓迎情報を送信する.
3.FTPコマンドの処理
(1)アクセス制御コマンド
◆user name(user)とpassword(pass)コマンド処理コードは以下の通りです.
UserコマンドとPasswordコマンドは、クライアント・ユーザーが入力したユーザー名とパスワードを送信するために使用されます.
◆CWD(CHANGE WORKING DIRECTORY)コマンド処理コードは以下の通り.
このコマンドは、作業ディレクトリをユーザーが指定したディレクトリに変更します.
◆CDUP(CHANGE TO PARENT DIRECTORY)コマンド処理コードは以下の通り.
このコマンドは、現在のディレクトリを上位レベルのディレクトリに変更します.
◆QUITコマンド処理コードは以下の通り.
このコマンドは、サーバへの接続を終了およびクローズし、GOOD BYEを出力します.
(2)伝達パラメータコマンド
◆Portコマンド処理コードは以下の通りです.
このコマンドを使用する場合、クライアントは、データを受信するための32ビットのIPアドレスと、16ビットのTCPポート番号を送信する必要があります.これらの情報は8ビットを1組とし,10進数伝送を用い,中間はカンマで区切られている.
◆TYPEコマンド処理コードは以下の通りです.
TYPEコマンドは、タイプ設定を完了します.
(3)FTPサービスコマンド
◆RETR(RETEIEVE)とSTORE(STORE)コマンド処理のコード
ファイル転送コマンドには、サーバからファイルRETRを取得することと、サーバにファイルSTORを送信することとがあり、この2つのコマンドの処理は非常に類似している.RETRコマンドを処理すると、まずユーザが取得するファイルの名前を取得し、名前に基づいてファイル入力ストリームを作成し、クライアントと一時ソケット接続を確立し、出力ストリームを得る.その後、ファイル入力ストリームのデータを読み出し、ソケット出力ストリームを介してクライアントに送信し、転送が完了した後、ストリームと一時ソケットを閉じる.
STORコマンドの処理も同様であるが,方向が正反対である.
◆DELE(DELETE)コマンド処理コードは以下の通りです.
DELEコマンドは、サーバ上の指定ファイルを削除するために使用します.
◆LIST命令処理コードは以下の通り.
LISTコマンドは、ファイルとディレクトリのリストを含むサーバ内の作業ディレクトリの下のディレクトリ構造をクライアントに返すために使用されます.このコマンドを処理するときは、まず一時的なソケットを作成してクライアントにディレクトリ情報を送信します.このソケットの宛先ポート番号はデフォルトで1で、現在の作業ディレクトリにFileオブジェクトを作成し、そのオブジェクトのlist()メソッドを使用してディレクトリの下のすべてのファイルとサブディレクトリ名を含む文字列配列を取得し、名前にファイル名に特有の「.」が含まれているかどうかによってディレクトリとファイルを区別します.最後に,得られた名前配列を一時ソケットを介してクライアントに送信する.
【概要】
FTP(File Transfer Protocolファイル転送プロトコル)は、インターネット上でファイルを転送するためのプロトコルです.インターネット上ではFTPサーバを介してファイルのアップロード(Upload)やダウンロード(Download)が可能です.FTPはリアルタイムオンラインサービスであり、それを使用する前にそのサービスを持つユーザー(ユーザー名とパスワード)でなければならない.作業時にクライアントはサーバー側のコンピュータにログインしなければならない.ユーザーがログインした後、ファイル検索とファイル転送などの操作を行うことができる.例えば、現在の作業ディレクトリ、列ファイルディレクトリの変更、転送パラメータの設定、ファイル転送などである.FTPを使用すると、テキストファイル、バイナリ実行ファイル、イメージファイル、サウンドファイル、データ圧縮ファイルなど、すべてのタイプのファイルを転送できます.
FTPコマンド
FTPの主な動作は,様々な命令に基づいている.一般的なコマンドは次のとおりです.
◆ASCII(テキスト)とBINARYバイナリモードを含む転送モードを設定する.
◆ディレクトリ操作、リモートコンピュータの現在のディレクトリ(cd、dir/lsコマンド)を変更または表示する.
◆接続操作、openコマンドはリモートコンピュータとの接続を確立するために使用される.closeコマンドは接続を閉じるために使用されます.
◆ファイルをリモートコンピュータに転送するためにputコマンドを送信する操作.mputコマンドは、複数のファイルをリモートコンピュータに転送するために使用されます.
◆取得操作、getコマンドはファイルを受信するために使用される.mgetコマンドは、複数のファイルを受信するために使用されます.
プログラミング構想
FTPの動作原理に基づいて、主関数の中で1つのサーバーソケットポートを創立して、クライアントの要求を待って、いったんクライアントの要求が受け入れられると、サーバーのプログラムは1つのサーバーのスレッドを創立して、クライアントの命令を処理します.クライアントがサーバ側とファイルの転送を行う必要がある場合は、ファイルの操作を完了するために新しいソケット接続を確立します.
プログラミングテクニックの説明
1.主関数設計
メイン関数では、サーバポートのリスニングとサービススレッドの作成を完了します.静的文字列変数initDirを使用して、サーバスレッドの実行時に存在する作業ディレクトリを保存します.サーバーの初期作業ディレクトリは、プログラム実行時にユーザーが入力したもので、デフォルトはCディスクのルートディレクトリです.
具体的なコードは以下の通りです.
public class ftpServer extends Thread{
private Socket socketClient;
private int counter;
private static String initDir;
public static void main(String[] args){
if(args.length != 0) {
initDir = args[0];
}else{ initDir = "c:";}
int i = 1;
try{
System.out.println("ftp server started!");
// 21
ServerSocket s = new ServerSocket(21);
for(;;){
//
Socket incoming = s.accept();
//
new ftpServer(incoming,i).start();
i++;
}
}catch(Exception e){}
}
2.スレッドクラスの設計
スレッドクラスの主な設計はrun()メソッドで実現される.run()法でクライアントのソケット情報を得,ソケットに基づいて入力ストリームと出力ストリームを得,クライアントに歓迎情報を送信する.
3.FTPコマンドの処理
(1)アクセス制御コマンド
◆user name(user)とpassword(pass)コマンド処理コードは以下の通りです.
if(str.startsWith("USER")){
user = str.substring(4);
user = user.trim();
out.println("331 Password");}
if(str.startsWith("PASS"))
out.println("230 User "+user+" logged in.");
UserコマンドとPasswordコマンドは、クライアント・ユーザーが入力したユーザー名とパスワードを送信するために使用されます.
◆CWD(CHANGE WORKING DIRECTORY)コマンド処理コードは以下の通り.
if(str.startsWith("CWD")){
String str1 = str.substring(3);
dir = dir+"/"+str1.trim();
out.println("250 CWD command succesful");
}
このコマンドは、作業ディレクトリをユーザーが指定したディレクトリに変更します.
◆CDUP(CHANGE TO PARENT DIRECTORY)コマンド処理コードは以下の通り.
if(str.startsWith("CDUP")){
int n = dir.lastIndexOf("/");
dir = dir.substring(0,n);
out.println("250 CWD command succesful");
}
このコマンドは、現在のディレクトリを上位レベルのディレクトリに変更します.
◆QUITコマンド処理コードは以下の通り.
if(str.startsWith("QUIT")) {
out.println("GOOD BYE");
done = true;
}
このコマンドは、サーバへの接続を終了およびクローズし、GOOD BYEを出力します.
(2)伝達パラメータコマンド
◆Portコマンド処理コードは以下の通りです.
if(str.startsWith("PORT")) {
out.println("200 PORT command successful");
int i = str.length() - 1;
int j = str.lastIndexOf(",");
int k = str.lastIndexOf(",",j-1);
String str1,str2;
str1="";
str2="";
for(int l=k+1;l
str1 = str2 + str.charAt(l);
}
for(int l=j+1;l<=i;l++){
str2 = str2 + str.charAt(l);
}
tempPort = Integer.parseInt(str1) * 16 *16 +Integer.parseInt(str2);
}
このコマンドを使用する場合、クライアントは、データを受信するための32ビットのIPアドレスと、16ビットのTCPポート番号を送信する必要があります.これらの情報は8ビットを1組とし,10進数伝送を用い,中間はカンマで区切られている.
◆TYPEコマンド処理コードは以下の通りです.
if(str.startsWith("TYPE")){
out.println("200 type set");
}
TYPEコマンドは、タイプ設定を完了します.
(3)FTPサービスコマンド
◆RETR(RETEIEVE)とSTORE(STORE)コマンド処理のコード
if(str.startsWith("RETR")){
out.println("150 Binary data connection");
str = str.substring(4);
str = str.trim();
RandomAccessFile outFile = new
RandomAccessFile(dir+"/"+str,"r");
Socket tempSocket = new Socket(host,tempPort);
OutputStream outSocket
= tempSocket.getOutputStream();
byte byteBuffer[]= new byte[1024];
int amount;
try{
while((amount = outFile.read(byteBuffer)) != -1){
outSocket.write(byteBuffer, 0, amount);
}
outSocket.close();
out.println("226 transfer complete");
outFile.close();
tempSocket.close();
}
catch(IOException e){}
}
if(str.startsWith("STOR")){
out.println("150 Binary data connection");
str = str.substring(4);
str = str.trim();
RandomAccessFile inFile = new
RandomAccessFile(dir+"/"+str,"rw");
Socket tempSocket = new Socket(host,tempPort);
InputStream inSocket
= tempSocket.getInputStream();
byte byteBuffer[] = new byte[1024];
int amount;
try{
while((amount =inSocket.read(byteBuffer) )!= -1){
inFile.write(byteBuffer, 0, amount);
}
inSocket.close();
out.println("226 transfer complete");
inFile.close();
tempSocket.close();
}
catch(IOException e){}
}
ファイル転送コマンドには、サーバからファイルRETRを取得することと、サーバにファイルSTORを送信することとがあり、この2つのコマンドの処理は非常に類似している.RETRコマンドを処理すると、まずユーザが取得するファイルの名前を取得し、名前に基づいてファイル入力ストリームを作成し、クライアントと一時ソケット接続を確立し、出力ストリームを得る.その後、ファイル入力ストリームのデータを読み出し、ソケット出力ストリームを介してクライアントに送信し、転送が完了した後、ストリームと一時ソケットを閉じる.
STORコマンドの処理も同様であるが,方向が正反対である.
◆DELE(DELETE)コマンド処理コードは以下の通りです.
if(str.startsWith("DELE")){
str = str.substring(4);
str = str.trim();
File file = new File(dir,str);
boolean del = file.delete();
out.println("250 delete command successful");
}
DELEコマンドは、サーバ上の指定ファイルを削除するために使用します.
◆LIST命令処理コードは以下の通り.
if(str.startsWith("LIST")) {
try{
out.println("150 ASCII data");
Socket tempSocket = new Socket(host,tempPort);
PrintWriter out2= new PrintWriter(tempSocket.getOutputStream(),true);
File file = new File(dir);
String[] dirStructure = new String[10];
dirStructure= file.list();
String strType="";
for(int i=0;i
if( dirStructure[i].indexOf(".") == -1) {
strType = "d ";}
else
{strType = "- ";}
out2.println(strType+dirStructure[i]);
}
tempSocket.close();
out.println("226 transfer complete");
}
catch(IOException e){}
LISTコマンドは、ファイルとディレクトリのリストを含むサーバ内の作業ディレクトリの下のディレクトリ構造をクライアントに返すために使用されます.このコマンドを処理するときは、まず一時的なソケットを作成してクライアントにディレクトリ情報を送信します.このソケットの宛先ポート番号はデフォルトで1で、現在の作業ディレクトリにFileオブジェクトを作成し、そのオブジェクトのlist()メソッドを使用してディレクトリの下のすべてのファイルとサブディレクトリ名を含む文字列配列を取得し、名前にファイル名に特有の「.」が含まれているかどうかによってディレクトリとファイルを区別します.最後に,得られた名前配列を一時ソケットを介してクライアントに送信する.