최근에 이어받기/이어올리기가 가능한 업로드/다운로드 프로그램의 구현 방법을 조사했습니다.
주어진 조건으로는 HTTP를 이용하며, 서버는 Java를 이용하고 클라이언트는 C++을 이용하는 것입니다. 조사 결과 이어받기는 구현이 쉬우나 이어올리기는 별도의 과정을 직접 설계하거나 해당 기능을 지원하는 라이브러리 등을 이용해야 했어요. 순서대로 말씀드리겠습니다.
1. 이어받기
이어받기 자체는 HTTP가 프로토콜 차원에서 자체 지원하고 있습니다. 클라이언트 측에서 파일 다운로드 요청을 보낼 때 헤더에 (“Accept-Ranges”, “bytes”)와 (“Range”, “bytes=범위”)를 포함하면 서버에서 해당 파일에서 헤더가 정해준 범위의 데이터만 준비해주게 됩니다. 이것을 Java로 구현한 코드는 아래와 같습니다. 실제로는 아래 코드와 같이 파일이 이미 있을 경우 크기를 구하여 그 다음부터 받을 수 있도록 해줘야 하고 엄밀하게는 URI의 파일명과 로컬 저장소의 파일명도 일치해야 합니다. 또 받은 파일을 체크섬으로 검증해야 할 것입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
final int DOWNLOAD_DONE = 0; final int DEFAULT_TIMEOUT = 600; long fileSize; long remains; long fileLength; String url_ = "http://127.0.0.1:8080/PDS/a.mov"; File file = new File("C:\\BIN\\a.bin"); if (!file.exists()) { file.createNewFile(); } RandomAccessFile output = null; output = new RandomAccessFile(file.getAbsolutePath(), "rw"); fileSize = output.length(); output.seek(fileSize); URL url = new URL(url_); URLConnection conn = url.openConnection(); conn.setRequestProperty("Accept-Ranges", "bytes"); conn.setRequestProperty("Range", "bytes=" + String.valueOf(fileSize) + '-'); conn.connect(); conn.setConnectTimeout(DEFAULT_TIMEOUT); conn.setReadTimeout(DEFAULT_TIMEOUT); remains = conn.getContentLength(); fileLength = remains + fileSize; if((remains <= DOWNLOAD_DONE) || (remains == fileSize)) { System.out.println("error"); } InputStream input = conn.getInputStream(); byte data[] = new byte[1024]; int count = 0; if (fileSize < fileLength) { while((count = input.read(data)) != -1) { output.write(data, 0, count); } } output.close(); input.close(); System.out.println("Success"); |
서버 측에서는 이어받기를 지원하기 위해 별도의 코드를 작성해줄 필요는 없으며 단지 HTTP 웹서버 기능이 구현되어 있어야 합니다. 그렇지 않으면 [NanoHttpd]와 같은 초소형 웹서버를 서버에 접합해도 됩니다.
2. 이어올리기
이어올리기에 해당하는 기능은 “Content-Range” 헤더를 기반으로 구축하면 되나 최근의 HTTP 명세에서는 요청에서 사용할 것을 금지하고 응답에서만 사용할 것을 강제하고 있습니다. Google Drive나 Dropbox 같은 클라우드 서비스에서도 이어올리기 기능은 독자적인 프로토콜을 구축하여 제공하고 있는데, 따라서 이어올리기 기능은 직접 구현해야 하는 것으로 판단됩니다. [출처]
[tus.io]는 오픈 커뮤니티에서 만든 공개 프로토콜(MIT 라이선스)로, 앞에서 얘기한 이어올리기 기능을 HTTP/1.1과 HTTP/2에 기반하여 구축한 것입니다. 재개 가능한 파일전송을 정교하게 구현하려면 업로드가 중지 및 재개되었을 때의 처리와 체크섬을 이용한 검증 등 다양한 기능이 있어야 하는데 tus.io는 이들을 모두 제공하면서도 프로토콜의 분량이 적습니다.
또한 오픈 커뮤니티에서 Java, Python, .NET, Javascript 등으로 이미 서버와 클라이언트를 구축 후 공개했기 때문에 기존의 솔루션에 쉽게 접합할 수 있으며 이용 중인 솔루션의 언어로 구현되지 않은 경우에도 구현할 내용이 적어 짧은 시간 내에 구현 후 서비스를 할 수 있을 것으로 판단합니다. [참조]
아래 그림은 tus.io에 기반한 파일 업로드 라이브러리 [uppy]의 데모 장면으로, 파일 전송의 일시중지 밎 재개가 가능한 모습입니다.
재개 가능한 업로드/다운로드는 FTP에서도 프로토콜 차원에서 지원하고 있기 때문에 FTP를 쓰는 것도 하나의 방법이며, 기술력에 자신이 있다면 직접 정교하게 프로토콜을 구축하여 구현하는 것도 방법입니다.