FIF's 코딩팩토리

자바(java)로 SFTP Client 프로그램 만들기 본문

Back-End/Java(자바)

자바(java)로 SFTP Client 프로그램 만들기

FIF 2019. 5. 8. 11:18
반응형

프로젝트명 - MyProgram

패키지명 - program

클래스명 - MySFTPClient

 

환경설정

Virtual Box를 통해 CentOS 를 서버로 지정해두고

WindowOS를 클라이언트로 지정 했습니다.

 

SFTP구현을 위해 오픈소스 라이브러리인 JSch 라이브러리를 사용합니다.

http://www.jcraft.com/jsch/

 

JSch - Java Secure Channel

JSch - Java Secure Channel JSch is a pure Java implementation of SSH2. JSch allows you to connect to an sshd server and use port forwarding, X11 forwarding, file transfer, etc., and you can integrate its functionality into your own Java programs. JSch is l

www.jcraft.com

접속하셔서 밑으로 내리다보면 Download컨텐츠에 .jar 파일을 받으시고 이클립스 빌드패스에서 라이브러리에 추가합니다.

 

SFTP에 접속하기 위해서는 username, 호스트주소(ip주소등), 패스워드가 필요합니다.

 

스캐너를 이용해 클라이언트 정보를 입력 받아 SFTP서버에 접속하는 방식으로 구현했습니다.

 

SFTP는 FTP에서 보안을 강화한 프로토콜인데,

JSch 오픈소스 라이브러리를 이용하여 SFTP프로그램을 만들려면 DH알고리즘이 필요합니다.

 

메인메소드 바로 아래  DH알고리즘을 쓰기위한 코드를 밑과 같이 입력해주시고

 

http://www.bouncycastle.org/java.html 

링크타고 들어가셔서 라이브러리를 다운로드 받으신후 빌드패스에 라이브러리를 추가하시면 됩니다.

 

구현명령어 : cd pwd get put quit ls rm mkdir chmod chown ln lcd lpwd

 

package program;

import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.Scanner;
import java.util.Vector;

import javax.crypto.KeyAgreement;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;

public class MySFTPClient {
	public MySFTPClient() {
	}

	public static void main(String[] args) {
		// DH알고리즘을 쓰기위한 코드
		Security.addProvider(new BouncyCastleProvider());
		try {
			KeyPairGenerator.getInstance("DH");
		} catch (NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		}
		try {
			KeyAgreement.getInstance("DH");
		} catch (NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		}

		Session session = null;
		Channel channel = null;
		JSch jsch = new JSch();

		Scanner scanner = new Scanner(System.in);
		System.out.print("계정 입력: ");
		String username = scanner.nextLine();
		System.out.print("호스트 주소 입력: ");
		String host = scanner.nextLine();
		System.out.print("비밀번호 입력: ");
		String password = scanner.nextLine();

		try {
			// 세션 객체 생성
			session = jsch.getSession(username, host, 22);
			// 비밀번호설정
			session.setPassword(password);
			// 호스트 정보를 검사하지 않음
			session.setConfig("StrictHostKeyChecking", "no");
			// 세션접속
			session.connect();
			// sftp채널열기
			channel = session.openChannel("sftp");
			// 채널접속
			channel.connect();
			System.out.println("Connected to user@" + host);
		} catch (JSchException e) {
			e.printStackTrace();
			System.out.println("접속에 실패했습니다.");
			// 실패시 시스템 종료
			System.exit(0);
		}

		ChannelSftp channelSftp = (ChannelSftp) channel;
		while (true) {
			System.out.print("sftp> ");
			String str = "";
			str = scanner.nextLine();
			String command = str.split(" ")[0];

			if (command.equals("cd")) {
				String p1 = str.split(" ")[1];
				try {
					channelSftp.cd(p1);
				} catch (SftpException e) {
					System.out.println("Couldn't stat remote file: No such file or directory");
				}
			} // end cd
			else if (command.equals("lcd")) {
				// lcd C:\Users\solulink
				String p1 = str.split(" ")[1];
				try {
					channelSftp.lcd(p1);
				} catch (SftpException e) {

					System.out.println("Couldn't change local directory to " + p1 + ": No such file or directory");
				}
			} // end lcd
			else if (command.equals("pwd")) {
				try {
					System.out.println("Remote working directory: " + channelSftp.pwd());
				} catch (SftpException e) {
					e.printStackTrace();
				}
			} // end pwd
			else if (command.equals("lpwd")) {
				// lpwd
				System.out.println("Local working directory: " + channelSftp.lpwd());
			} // end lpwd
			else if (command.equals("get")) {
				// centos.txt
				String p1 = str.split(" ")[1];
				// C:\Users\solulink
				String p2 = str.split(" ")[2];
				try {
					channelSftp.get(p1, p2);
				} catch (SftpException e) {
					System.out.println("Ex)get centos.txt C:\\Users\\solulink");
				}
			} // end get
			else if (command.equals("put")) {
				String p1 = str.split(" ")[1];
				try {
					channelSftp.put(p1);
				} catch (SftpException e) {
					System.out.println("Ex)put window.txt");
				}
			} // end put
			else if (command.equals("ls") || command.equals("dir")) {
				String path = ".";
				try {
					// 가변길이의 배열
					Vector vector = channelSftp.ls(path);
					if (vector != null) {
						for (int i = 0; i < vector.size(); i++) {
							Object obj = vector.elementAt(i);
							if (obj instanceof ChannelSftp.LsEntry) {
								System.out.println(((ChannelSftp.LsEntry) obj).getLongname());
							}
						}
					}
				} catch (SftpException e) {
					System.out.println(e.toString());
				}
			} // end ls
			else if (command.equals("rm")) {
				try {
					String p1 = str.split(" ")[1];
					channelSftp.rm(p1);
				} catch (SftpException e) {
					System.out.println("Couldn't delete file: No such file or directory");
				}
			} // end rm
			else if (command.equals("mkdir")) {
				String p1 = str.split(" ")[1];
				try {
					channelSftp.mkdir(p1);
				} catch (SftpException e) {
					e.printStackTrace();
				}
			} // end mkdir
			else if (command.equals("rmdir")) {
				String p1 = str.split(" ")[1];
				try {
					channelSftp.rmdir(p1);
				} catch (SftpException e) {
					System.out.println("Couldn't remove diretory: No such file or directory");
				}
			} // end rmdir
			else if (command.equals("chmod")) {
				//접근권한 설정
				// chmod 777 window.txt(rwx:7 x:1 wx:3 r-x:5)
				String p1 = str.split(" ")[1];
				String p2 = str.split(" ")[2];
				try {
					channelSftp.chmod(Integer.parseInt(p1), p2);
				} catch (NumberFormatException e) {
					e.printStackTrace();
				} catch (SftpException e) {
					e.printStackTrace();
				}
			} // end chmod
			else if (command.equals("chown")) {
				// 파일소유권변경->일반계정에 root권한 부여(vi /etc/passwd->UID와GID변경)
				// 리눅스에서 cat /etc/passwd
				// jinpyolee : 1000 sftpuser : 1004
				// chown 1000 window.txt
				String p1 = str.split(" ")[1];
				String p2 = str.split(" ")[2];
				try {
					channelSftp.chown(Integer.parseInt(p1), p2);
				} catch (NumberFormatException e) {
					e.printStackTrace();
				} catch (SftpException e) {
					e.printStackTrace();
				}
			} // end chown
			else if (command.equals("ln") || (command.equals("symlink"))) {
				// 링크파일 생성(rwxrwxrwx, 리눅스에서 하늘색으로 나옴)
				// ln window.txt win.txt
				String p1 = str.split(" ")[1];
				String p2 = str.split(" ")[2];
				try {
					channelSftp.symlink(p1, p2);
				} catch (SftpException e) {
					e.printStackTrace();
				}
			} // end ln
			else if (command.equals("quit")) {
				channelSftp.quit();
				// 반복문 나가서 종료
				break;
			} // end quit
			else {
				System.out.println("Invalid command.");
			}
		} // end while
			// 연결해제
		channelSftp.disconnect();
		// 스캐너자원반납
		scanner.close();
		// 시스템종료
		System.exit(0);
	}// end main()

}// end class

자바로 만든 SFTP Client프로그램 시작화면
Windows의 명령프롬프트(cmd)를 사용하여 SFTP방식으로 서버에 연결하는 모습

 

최대한 CMD창과 비슷하게 구현하도록, 명령어를 띄어쓰기 ( ) 단위로 구분하여 split메소드를 사용해

해당 명령어로 분기하도록 했습니다.

 

구글에 있는 대부분 sftp프로그램은 하드코딩이여서 실제 사용하는 환경과 최대한 똑같도록 구현해봤습니다.

 

궁금한점 있으시면 댓글 남겨주세요~

반응형
Comments