ひでっぷの技術メモ

はてなダイアリーから移行しました

FTPクライアントの作成(Socket編)

JavaでのFTPクライアントの作成方法。
まずはべたなSocketを使った方法。

参考にしたのはFTPの仕組みJavaでHello World FTP編


private Socket ctrlSocket;
private OutputStream ctrlOutput;
private InputStream ctrlInput;

/**
* FTPへuploadする
* @param data String
* @param fileName String
* @throws UnknownHostException
* @throws IOException
*/
public void upload(String data, String fileName) throws UnknownHostException,
IOException {
char inbuffer;
int i;

// FTPサーバーへ接続します
ctrlSocket = new Socket("192.168.xxx.xxx",21);
localHostAddress = ctrlSocket.getLocalAddress().getAddress();
ctrlOutput = new PrintWriter(ctrlSocket.getOutputStream());
ctrlInput = new
BufferedReader(new InputStreamReader(ctrlSocket.
getInputStream()));
inbuffer = new char[1000];
i = ctrlInput.read(inbuffer);
// ユーザー認証します
String sendCommand = "USER ユーザー名";

ctrlOutput.println(sendCommand);
ctrlOutput.flush();
inbuffer = new char[1000];
i = ctrlInput.read(inbuffer);
sendCommand = "PASS パスワード";
ctrlOutput.println(sendCommand);
ctrlOutput.flush();
inbuffer = new char[1000];
i = ctrlInput.read(inbuffer);
// 指定したディレクトリに移動します
sendCommand = "CWD 指定ディレクトリ";
ctrlOutput.println(sendCommand);
ctrlOutput.flush();
inbuffer = new char[1000];
i = ctrlInput.read(inbuffer);
// アスキーモードに変更します
sendCommand = "TYPE A";

ctrlOutput.println(sendCommand);
ctrlOutput.flush();
inbuffer = new char[1000];
i = ctrlInput.read(inbuffer);
// アップロードします
Socket dataSocket = dataConnection("STOR " + fileName);
OutputStream outstr = dataSocket.getOutputStream();
byte buf = data.getBytes();
outstr.write(buf);
outstr.flush();
dataSocket.close();
inbuffer = new char[1000];
i = ctrlInput.read(inbuffer);

// 接続を閉じます
ctrlOutput.close();
ctrlInput.close();
ctrlSocket.close();
}

/**
* データ送受信用ソケットを取得します
*/
private Socket dataConnection(String ctrlcmd) throws IOException,
UnknownHostException {
ServerSocket serverDataSocket = null;
try {
String cmd = "PORT ";
   //データコネクション用のSocketサーバーを生成する
serverDataSocket = new ServerSocket(0,1);

for (int i = 0; i < 4; i++) {
cmd = cmd + (localHostAddress[i] & 0xff) + ",";
}
cmd = cmd + ( ( (serverDataSocket.getLocalPort()) / 256) & 0xff)
+ ","
+ (serverDataSocket.getLocalPort() & 0xff);

ctrlOutput.println(cmd);
ctrlOutput.flush();
ctrlOutput.println(ctrlcmd);
ctrlOutput.flush();
//FTPサーバーから接続してきたSocketをデータコネクションとして使用する
Socket dataSocket = null;
dataSocket = serverDataSocket.accept();
return dataSocket;
}
finally {
if (serverDataSocket != null) {
serverDataSocket.close();
}
}
}

FTPの仕組みに書いてあるようにFTPってのはコントロールコネクションとデータコネクションとの2つのコネクションで成り立っているらしい。
それをそのままソースコードにしたのが上なんですよね。
本当はctrlInputがread()したFTPサーバー側の返答を見てユーザーやパスワードが違っていたらとか途中で切断されたらとか細かいことを考えないといけませんが、正常に行くのが前提であればこれで十分です。
実際に動かしてみましたが全く問題なくFTPサーバーへのUploadができました。