2. FTP 통신으로 파일 전송 Last updated: 2023-10-17 10:30:59

FTP는 File Transfer Protocol의 약자로 TCP/IP 네트워크 상에서 이용자와 서버 간에 파일을 송수신 하기 위한 통신 프로토콜을 말한다. 주로 파일 전송을 위해 개발된 프로토콜 이므로 대량의 파일 전송에 적합한다.

2.1 FileZilla FTP 서버 설치

FileZilla는 FTP 서버 기능을 무료로 제공한다. 따라서, PC 상에 FTP 서버를 구성하거나 간단히 FTP 서버를 테스트 해볼 때 편하게 사용할 수 있다. FileZilla를 이용해 윈도우 PC 상에서 FTP 서버를 구성하는 방법을 설명한다.


1단계: FileZilla 사이트로 이동

웹 브라우저에서 아래 주소로 이동한다.

image

[그림 7-2-1] filezilla-project.org 사이트 화면


오른쪽의 Download FileZilla Server 버튼을 클릭한다.



2단계: FileZilla Server 프로그램 다운로드

FileZilla Server 다운로드 페이지에서 “Download FileZilla Server” 버튼을 클릭한다.

image

[그림 7-2-2] FileZilla 서버 버전 다운로드 화면



3단계: FileZilla Server 프로그램 무료 버전 다운로드

다운로드 팝업이 뜨면 가장 왼쪽 무료 버전의 “Download” 버튼을 클릭해 설치 파일을 다운로드 받는다.

image

[그림 7-2-3] 가격 별 FileZilla 기능 비교 및 다운로드


다운로드 받은 설치 프로그램을 실행한다.

License Agrement 창에서 ‘I Agree’ 버튼을 클릭한다.


image

[그림 7-2-4] FileZilla 서버 버전 설치 시작 화면


컴포넌트 선택(Choose Components) 창에서 옵션을 기본으로 두고 ‘Next >’ 버튼을 클릭한다.


image

[그림 7-2-5] FileZilla 설치 옵션 선택 화면


설치 위치(Choose Install Location) 창에서 프로그램이 설치될 위치를 확인하고 ‘Next >’ 버튼을 클릭한다.


image

[그림 7-2-6] FileZilla 설치 위치 설정 화면


시작 메뉴 설정(Choose Start Menu Folder)을 그대로 두고 ‘Next >’ 버튼을 클릭한다.


image

[그림 7-2-7] FileZilla 메뉴 그룹 구성 설정 화면


다음은 서버 설정(Server settings) 이다. 설정을 그대로 두어도 되지만 기본 설정대로 진행이 된다면 컴퓨터가 시작될 때 FileZilla FTP Server도 자동으로 시작된다.

만일 서버로 운영하려면 ‘Install as service, started with Windows (default)’를 선택한다. 하지만 FTP 서버 테스트만 원한다면 필요할 때만 서버를 실행하면 되기 때문에 ‘Install as service, start manually’를 선택한다.

지금은 두 번째 옵션 (start manual)을 선택한다. 옵션 선택을 마쳤으면 ‘Next >’ 버튼을 클릭한다.


image

[그림 7-2-8] FileZilla 서버 설정 선택 화면


다음은 관리자 설정이다. 관리자 접근을 허용하는 포트는 14148번이다. 그대로 두고 관리자 비밀번호를 입력한다. 관리자 비밀번호를 잊지 않도록 주의한다. 설정이 완료되었다면 ‘Next >’ 버튼을 클릭한다.


image

[그림 7-2-9] FileZilla 기본 포트 및 관리자 비밀번호 설정 화면


관리자 설정을 기본으로 두고 ‘Install’ 버튼을 클릭한다.


image

[그림 7-2-10] FileZilla 설치를 위해 사용하는 대상 설정 화면


이제 프로그램 설치가 진행된다.


image

[그림 7-2-11] FileZilla 프로그램 설치 진행 화면


설치가 완료되면 관리자 프로그램인 Administration interface 가 실행된다. ‘Connect to Server…’ 버튼을 클릭한다.


image

[그림 7-2-12] FileZilla 설치 완료 후 실행된 화면


Connection 창에서 로컬에 있는 FTP Server에 접속할 것이므로 Host는 127.0.0.1 혹은 localhost라고 입력한다.

Port는 설치할 때 확인한 번호이고, 기본값을 그대로 두었다면 14148이다.

관리자 페이지에서 입력한 관리자 비밀번호를 입력하고 ‘OK’ 버튼을 클릭한다.


image

[그림 7-2-13] FileZilla 서버 연결 설정 화면


관리자 로그인을 성공하면 다음과 같은 화면이 보인다.


image

[그림 7-2-14] FileZilla 관리자 로그인 후 관리 화면


이제 접속 가능한 FTP 서버를 생성하기 위해 메뉴에서 [Server > Configure]를 클릭한다.


image

[그림 7-2-15] FileZilla 서버 추가 메뉴


우선 Server Listeners에서 서버가 수신할 네트워크 정보를 설정한다. Address는 0:0:0:0인데 이렇게 되면 모든 IP에서 들어오는 요청에 대해 처리하겠다는 의미이다. Port가 21번인데 보통 FTP에서 가장 많이 사용하는 포트이다. 테스트를 위한 것이니 우선 기본 설정으로 둔다.


image

[그림 7-2-16] FileZilla 서버 설정 화면


다음은 사용자 정보를 지정한다.

좌측 메뉴에서 ① Users를 클릭한다. 하단에 ②Add 버튼을 클릭하고 추가된 사용자 목록에서 이름을 ③에서 test1이라고 입력하였다.

우측 사용자 설정에서 ④인증 방식(Authentication)에서 비밀번호가 필요한 사용자를 위해 ‘Require a password to log in’을 선택하고 그 아래 사용할 비밀번호를 입력한다. 다음은 접속 후 보여질 위치 설정이다. ⑤Mount points에서 아래 ‘Add’ 버튼을 클릭하고 Virtual path에 ‘/’를 입력한다. 또한 Native path에 접속 후 보여질 폴더의 경로명을 입력한다. 이 부분이 FTP 서버의 파일 Root이다. 여기서는 D 드라이브 아래에 ftp_root 라고 폴더를 만들어서 지정했다.

설정이 끝났다면 맨 하단에 ‘OK’ 버튼을 클릭한다.


image

[그림 7-2-17] FileZilla 서버 사용자 설정 화면


이제 FTP 서버가 정상적으로 작동하는지 확인해보자.

지금은 WinSCP라는 FTP Client 프로그램을 이용한 테스트 이다. WinSCP는 무료로 사용하기에 훌륭한 FTP 프로그램이다. WinSCP를 실행하고 세션 정보를 설정한다. 파일 프로토콜은 FTP로 설정하고, 호스트 이름은 127.0.0.1, 포트 번호는 21, 사용자 이름과 비밀번호를 입력하고 하단에 "로그인" 버튼을 클릭한다.


image

[그림 7-2-18] WinSCP로 생성된 서버 연결 설정 화면


접속이 완료되면 FTP Server의 Root 폴더가 다음과 같이 보인다.


image

[그림 7-2-19] WinSCP로 FTP 서버 접속된 화면


실제 탐색기에서 확인한 D: ftp_root은 다음과 같다. ftp 프로그램으로 접속한 내용과 동일하다.


image

[그림 7-2-20] FTP 서버 루트 폴더 화면



2.2 FTP 서버 접속


2.2.1 서버 접속하기

우선 FTP 서버에 접속이 되는지 확인해보자. 파이썬에서 FTP 접속을 위해서는 ftplib 라는 모듈을 제공한다. ftplib 모듈을 통해 위에서 설정한 FTP 서버에 접속해 본다. 다음은 FTP 서버에 접속하는 기본적인 예제이다.

[예제 7- 9] FTP 서버 접속하기

# [1] 모듈 임포트
import ftplib

# [2] 서버 접속
ftp = ftplib.FTP(host='127.0.0.1')

# [3] 사용자 로그인
res = ftp.login(user='test1', passwd='testpw')
print(res)

# [4] 연결 닫기
res = ftp.quit()
print(res)

[결과]

230 Login successful.
221 Goodbye.

위 예제에 대해 설명한다.

  • [1]에서 ftplib 모듈을 임포트한다.

  • [2]에서 서버에 접속한다. 서버 주소를 입력한다. 기본 포트는 21번이다. 만일 ftp 서버의 포트 번호가 다르다면 connect( ) 함수를 이용해 port를 지정해준다.

  • [3]에서 접속 모드를 설정한다. FTP는 액티브(Active) 모드와 패시브(Passive) 모드를 지원한다.

  • [4]에서 사용이 끝난 FTP 연결을 종료한다.

  • 결과를 보면 사용자 로그인 후 "230 Login successful"이라는 메시지가 출력 되었고, quit( ) 함수 이후 "221 Goodbye" 메시지가 출력 되었다.

Hint ! Active 모드 vs. Passive 모드

FTP는 기본적으로 Active 모드의 Passive 모드를 지원한다. Active 모드는 클라이언트가 서버 접속할 때 서버가 접속할 수 있는 포트를 서버에 알려주고 서버가 해당 포트를 통해 클라이언트에 접속하는 방식이다. Passive 모드는 클라이언트에서 서버에 접속하는 것이다.



2.2.2 FTP 서버 파일 목록 조회

FTP 서버에 접속하면 현재 위치에 존재하는 파일 및 폴더 목록을 조회할 수 있다. 다음은 접속한 위치에 존재하는 파일 목록을 조회하는 예제이다.

[예제 7- 10] FTP 서버 파일 목록 조회하기

# [1] 모듈 임포트
import ftplib

# [2] 서버 접속
ftp = ftplib.FTP(host='127.0.0.1')

# [3] 사용자 로그인
res = ftp.login(user='test1', passwd='testpw')
print(res)

# [4] 서버 파일 목록 조회
dirs = ftp.nlst()
print(dirs)

# [5] 연결 닫기
res = ftp.quit()
print(res)

[결과]

230 Login successful.
['welcome.txt']
221 Goodbye.

위 예제에 대해 설명한다.

  • [1]에서 ftplib 모듈을 임포트한다.

  • [2]에서 FTP 객체를 생성한다.

  • [3]에서 사용자 로그인을 한다.

  • [4]에서 서버의 현재 위치에 해당하는 파일 목록을 조회한다.

  • [5]에서 사용이 끝난 FTP 연결을 종료한다.

  • 결과를 보면 사용자 로그인 후 [’welcome.txt’]라는 파일의 목록을 출력하고 있다.


2.2.3 FTP 서버 폴더 생성

FTP 서버에 접속해 현재 위치에 새로운 폴더를 만들어 본다. 다음은 FTP 서버에 접속한 후 현재 위치에 ‘test’라는 폴더를 생성하는 예제이다.

[예제 7- 11] FTP 서버에 폴더 생성하기

# [1] 모듈 임포트
import ftplib

# [2] 서버 접속
ftp = ftplib.FTP(host='127.0.0.1')

# [3] 사용자 로그인
res = ftp.login(user='test1', passwd='testpw')
print(res)

# [4] 새로운 폴더 만들기
res = ftp.mkd('test')
print(res)

# [5] 연결 닫기
res = ftp.quit()
print(res)

[결과]

230 Login successful.
/test
221 Goodbye.

위 예제에 대해 설명한다.

  • [1]에서 ftplib 모듈을 임포트한다.

  • [2]에서 FTP 객체를 생성한다.

  • [3]에서 사용자 로그인을 한다.

  • [4]에서 서버의 현재 위치에 ‘test’라는 디렉토리를 생성한다.

  • [5]에서 사용이 끝난 FTP 연결을 종료한다.

위의 코드가 실행되고 나서 ftp_root 폴더를 가보면 다음과 같이 test 폴더가 생성되어 있음을 확인할 수 있다.


image

[그림 7-2-21] FTP 루트 폴더 상태 조회


다음은 FTP를 통해 파일이나 폴더를 다루는데 유용한 함수들 이니 참고하기 바란다.

  • FTP.rename(fromname, toname) : 서버의 파일 이름을 변경한다.

  • FTP.delete(filename) : 서버의 파일을 삭제한다.

  • FTP.cwd(pathname) : 서버에서 현재 디렉토리 위치를 설정한다.

  • FTP.mkd(pathname) : 서버에서 현재 디렉토리에 새 디렉토리를 만든다.

  • FTP.pwd( ) : 서버에서 현재 디렉토리 경로명을 반환한다.

  • FTP.rmd(dirname) : 서버에서 디렉토리를 삭제한다.


2.3 파일 다운로드


2.3.1 텍스트 파일 다운로드

FTP 서버에 있는 파일을 다운로드할 때는 FTP.retrbinary( ) 함수를 사용한다. 다음은 서버에 있는 welcom.txt 파일을 다운로드 받는 예제이다.

[예제 7- 12] FTP 텍스트 파일 다운로드하기

# [1] 모듈 임포트
import ftplib

# [2] 서버 접속
ftp = ftplib.FTP(host='127.0.0.1')

# [3] 사용자 로그인
res = ftp.login(user='test1', passwd='testpw')
print(res)

# [4] 파일 다운로드 및 저장
with open('welcome.txt', 'wb') as fp:
    res = ftp.retrbinary('RETR welcome.txt', fp.write)
    print(res)

# [5] 연결 닫기
res = ftp.quit()
print(res)

[결과]

230 Login successful.
226 Operation successful
221 Goodbye.

위 예제에 대해 설명한다.

  • [1]에서 ftplib 모듈을 임포트한다.

  • [2]에서 FTP 객체를 생성한다.

  • [3]에서 사용자 로그인을 한다.

  • [4]에서 다운로드할 파일 객체를 생성하고, retrbinary( ) 함수를 이용해 파일의 바이너리 데이터를 다운 받아 파일 객체에 쓴다.

  • [5]에서 사용이 끝난 FTP 연결을 종료한다.


2.3.2 이미지 파일 다운로드

FTP.retrbinary( ) 함수를 이용하면 바이너리 데이터를 다운로드 받으므로 파일이 텍스트 형식이거나 이미지 형식이거나 상관 없이 다운로드 받을 수 있다. 다음은 서버에 있는 moon.jpg 파일을 다운로드 받는 예제이다.

[예제 7- 13] FTP로 이미지 파일 다운로드 하기

# [1] 모듈 임포트
import ftplib

# [2] 서버 접속
ftp = ftplib.FTP(host='127.0.0.1')

# [3] 사용자 로그인
res = ftp.login(user='test1', passwd='testpw')
print(res)

# [4] 파일 다운로드 및 저장
with open('moon.jpg', 'wb') as fp:
    res = ftp.retrbinary('RETR moon.jpg', fp.write)
    print(res)

# [5] 연결 닫기
res = ftp.quit()
print(res)

[결과]

230 Login successful.
226 Operation successful
221 Goodbye.

위 예제에 대해 설명한다.

  • [1]에서 ftplib 모듈을 임포트한다.

  • [2]에서 FTP 객체를 생성한다.

  • [3]에서 사용자 로그인을 한다.

  • [4]에서 다운로드할 파일 객체를 생성하고, retrbinary( ) 함수를 이용해 파일의 바이너리 데이터를 다운 받아 파일 객체에 쓴다.

  • [5]에서 사용이 끝난 FTP 연결을 종료한다.


2.4 파일 업로드


2.4.1 일반 파일 업로드

ftplib 모듈을 이용해 로컬의 파일을 FTP 서버로 전송하려면 storbinary( ) 함수를 이용한다.

[예제 7- 14] FTP 파일 업로드하기

# [1] 모듈 임포트
import ftplib

# [2] 서버 접속
ftp = ftplib.FTP(host='127.0.0.1')

# [3] 사용자 로그인
res = ftp.login(user='test1', passwd='testpw')
print(res)

# [4] 파일 업로드
with open(file="sokcho.jpg", mode='rb') as fp:
    res = ftp.storbinary("STOR sokcho.jpg", fp)
    print(res)

# [5] 현재 서버 목록 조회
print(ftp.nlst())
   
# [6] 연결 닫기
res = ftp.quit()
print(res)

[결과]

230 Login successful.
226 Operation successful
['moon.jpg', 'sokcho.jpg', 'test', 'welcome.txt']
221 Goodbye.

위 예제에 대해 설명한다.

  • [1]에서 ftplib 모듈을 임포트한다.

  • [2]에서 FTP 객체를 생성한다.

  • [3]에서 사용자 로그인을 한다.

  • [4]에서 업로드할 파일을 바이너리 읽기 모드 (’rb’)로 열고 storbinary( ) 함수를 이용해 서버로 전송한다. sortbinary( ) 함수의 첫 번째 인자는 저장 명령인 ‘STOR’과 함께 저장할 파일명을 지정해야 한다.

  • [5]파일 전송이 끝난 후 서버 파일 목록을 조회하여 출력한다. 출력 결과에 보면 ‘sokcho.jpg’ 파일이 포함되어 있다. 정상적으로 업로드 된 것이다.

  • [6]에서 사용이 끝난 FTP 연결을 종료한다.


2.4.2 대용량 파일 업로드

FTP 프로토콜을 이용해 파일을 업로드하면 용량이 큰 파일을 업로드 해야 할 경우가 많이 있다. 이러한 경우 파일 업로드 상태를 확인하는 것이 필요하다. 이번에 알아볼 내용은 FTP 서버로 전송할 때 전송할 블록 크기를 제어하고, 진행 중인 상황을 확인하기 위해 Callback 함수를 사용하는 법에 대해 알아보자. storbinary( ) 함수의 인자 중에서 옵션으로 사용할 수 있는 파라미터로 blocksize와 callback이 있다. 이 두 인자를 이용해 서버 전송 단계를 세밀하게 조정할 수 있다. 다음은 대용량 파일을 FTP 서버에 전송하는 예제이다.

[예제 7- 15] FTP 대용량 파일 업로드하기

# [1] 모듈 임포트
import ftplib
from os import path

# [2] 파일 정보 얻기
block_size = 1048576 # (1024 * 1024)
file_size = path.getsize("limitless.mp4")
total_iteraction = int(file_size / block_size)
print(f"total file size: {file_size:,} byte")

# [3] Callback 함수 구현
current_progress = 0
def UploadTracker(block):
    global current_progress
    global total_iteraction
    
    print(f"{current_progress / total_iteraction * 100:.2f}%", end="\r")
    current_progress += 1

# [4] 서버 접속
ftp = ftplib.FTP(host='127.0.0.1')

# [5] 사용자 로그인
res = ftp.login(user='test1', passwd='testpw')
print(res)

# [6] 파일 업로드
with open(file="limitless.mp4", mode='rb') as fp:
    res = ftp.storbinary("STOR limitless.mp4", fp, callback=UploadTracker, blocksize=block_size)
    print(res)

# [7] 현재 서버 목록 조회
print(ftp.nlst())
   
# [8] 연결 닫기
res = ftp.quit()
print(res)

[결과]

total file size: 2,160,848,402 byte
230 Login successful.
Progress: 47.81% ..
226 Operation successful
['limitless.mp4', 'moon.jpg', 'sokcho.jpg', 'test', 'welcome.txt']
221 Goodbye.

위 예제에 대해 설명한다.

  • [1]에서 ftplib 모듈을 임포트한다.

  • [2]에서 업로드할 파일의 사이즈 정보를 얻는다. 그리고 전송할 block 크기인 8192로 나누어 몇 번 동안 반복될지 total_iteration 변수 값을 계산한다. block_size는 한 번에 전송할 블록의 크기이다. 기본 값은 8,192(8KB)이다. 우리는 1,048,576(1MB)로 변경했다.

  • [3]에서 callback 함수를 정의한다. callback 함수는 FTP 서버로 파일을 전송할 때 한 개의 block 전송이 끝날 때마다 자동으로 호출되는 함수이다. 함수 내에서 외부 변수인 current_progress 와 total_iteration 변수를 사용하도록 global 변수로 만들고, 함수가 호출될 때마다 current_progress값을 1씩 증가 시킨다.

  • [4]에서 FTP 객체를 생성한다.

  • [5]에서 사용자 로그인을 한다.

  • [6]에서 업로드할 파일을 바이너리 읽기 모드 (’rb’)로 열고 storbinary( ) 함수를 이용해 서버로 전송한다. sortbinary( ) 함수의 첫 번째 인자는 저장 명령인 ‘STOR’과 함께 저장할 파일명을 지정해야 한다. callback으로 호출될 함수명 UploadTracker을 지정하고, blocksize는 1,048,576 으로 지정한다.

  • [7]파일 전송이 끝난 후 서버 파일 목록을 조회하여 출력한다. 출력 결과에 보면 ‘limitless.mp4’ 파일이 포함되어 있다. 정상적으로 업로드 된 것이다.

  • [6]에서 사용이 끝난 FTP 연결을 종료한다.

  • 출력 결과를 보면 ‘Progress: 47.81%’ 라고 현재의 진행 상황이 백분율로 표시되는 것을 확인할 수 있다.