지난 시간에 네트워크 프로그래밍에 대해서 배웠다.
오늘은 이를 이용해서 파일 전송 프로그램을 만들어 보자.
- 용어정리
- File 클래스
- 파일 전송을 위한 고려 사항
- 전송 과정
ServerSocket
: 클라이언트에서 접속 요청이 올 때마다 대응 Socket을 만들어 냄
Socket
: 통신을 위한 논리적 단말기
Stream
: 데이터가 오고 가는 통로, 데이터를 주고 받는 모든 환경에서 쓰이는 개념.
.getOutputStream
: 인스턴스에서 통로를 가져옴
DateOutputStream
: 그 통로를 업그레이드하여 더 많은 데이터가 오고 가게 함.
DAO
: DB에 접근해 데이터를 보관, 정렬과 관련된 메서드와 변수들만 가지고 있는 클래스에 붙이는 명칭
DTO
: 데이터를 저장하는 인스턴스를 만들어내는 클래스에 붙이는 명칭
flush
: 데이터 버퍼 비우는 기능.
객체지향에 따라 우리가 여태 만든 클래스는 물리적으로 존재하는 것을 메모리에 논리적으로 투영시키는 것이었다.
이를 따라 File
클래스는 HDD, SSD 같은 저장소에 있는 데이터를 CPU에서 처리하기 위해 RAM에 투영시키기 위해 존재한다.
File file = new file(“C:/test/music.mp3”);
따라서 new file(“파일 주소”)
로 인스턴스를 생성하는 순간 HDD에 있는 파일의 메타데이터가 메모리로 올라온다. 이때, 올라온 것은 파일 자체의 내용으로 이를 이용하여 크기, 존재유무 등을 알 수 있다.
System.out.println(file.exists());
System.out.println(file.length());
System.out.println(file.isDirectory());
System.out.println(file.isFile());
System.out.println(file.getParentFile());
System.out.println(file.getPath());
File[]
을 만들어 내부의 각 기능을 사용할 수 있다.File[] files = file.listFiles();
for(File f : files) {
System.out.println(f.getName());
}
네트워크 프로그램을 만들었을 때처럼 Stream
과 Socket
만 있으면 가능하리라 생각하면 오산이다.
물론 원리는 똑같지만, 디테일한 설정이 다르다.
먼저 우리가 파일의 위치를 고려해야 한다.
우리가 보낼 파일, 또는 받은 파일은 HDD와 같은 보조기억장치에 위치한다.
그리고 이를 처리하기 위해선 RAM이라는 주기억장치에 올려놔야만 CPU가 처리한다.
따라서 HDD에 있는 것을 RAM으로 올리는 것부터 시작한다.
PC A → PC B 로 전송하는 과정은 다음과 같다.
[ A : HDD → RAM ] → InterNet → [ B ; RAM → HDD ]
기본적인 전송이 사용되는 코드들만 작성하겠다.
File file = new File("C:/test/" + loadingFile); // 로딩 파일 인스턴스 생성
FileInputStream fis = new FileInputStream(file); // file이 들어올 InputStream 을 개방
DataInputStream fsis = new DataInputStream(fis); // 사용하기 편하게 만듬
byte[] filecontants = new byte[(int)file.length()]; // 파일을 담을 공간을 RAM에 생성
fsis.readFully(filecontants); // RAM에 파일 업로드
DataOutputStream dos = new DataOutputStream(sock.getOutputStream()); // 파일을 보낼 Stream 개방
dos.writeLong(filecontants.length); // 클라이언트 쪽에 파일의 크기를 전달
dos.write(filecontants); // 파일 전송
dos.flush(); // 버퍼 비우기
// RAM(B)
byte[] fileContants = new byte[(int)dis.readLong()]; // 전달받은 크기만큼 RAM에 공간 생성
dis.readFully(fileContants) // RAM에 파일 저장
File dest = new File("C:/목적지/"+downFile); // 다운 받을 장소를 RAM으로 끌어옴
FileOutputStream fos = new FileOutputStream(dest); // RAM - HDD 사이에 Stream 개방
DataOutputStream dfos = new DataOutputStream(fos);
dfos.write(fileContants); // dest에 정보를 입력
dfos.flush(); // 버퍼 비우기
dfos.close(); // Stream 폐쇄
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws Exception{
Scanner sc = new Scanner(System.in);
Socket sock = new Socket("", 15000);
DataInputStream dis = new DataInputStream(sock.getInputStream());
DataOutputStream dos = new DataOutputStream(sock.getOutputStream());
while(true) {
int length = dis.readInt();
for (int i = 0; i<length; i++) {
String getName = dis.readUTF();
System.out.println(getName);
}
System.out.print("다운 받으실 파일명을 입력하세요 : ");
String downFile = sc.nextLine();
dos.writeUTF(downFile);
byte[] fileContants = new byte[(int)dis.readLong()];
dis.readFully(fileContants);
File dest = new File("C:/목적지/"+downFile);
FileOutputStream fos = new FileOutputStream(dest);
DataOutputStream dfos = new DataOutputStream(fos);
dfos.write(fileContants);
dfos.flush();
dfos.close();
System.out.println(dest.getName()+" 수신 완료!");
System.out.print("종료하시겠습니까? y | n : ");
String menu = sc.nextLine();
if (menu.equals("y")) {
System.exit(0);
} else {
continue;
}
}
}
}
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
try {
ServerSocket server = new ServerSocket(15000);
Socket sock = null;
while(true) {
System.out.println("클라이언트 접속 대기 중");
sock = server.accept();
System.out.println(sock.getInetAddress()+ " 접속");
try {
while(true) {
DataOutputStream dos = new DataOutputStream(sock.getOutputStream());
DataInputStream dis = new DataInputStream(sock.getInputStream());
File dir = new File("C:/test/");
File[] files = dir.listFiles();
dos.writeInt(files.length);
for (File f : files) {
dos.writeUTF(f.getName());
}
String loadingFile = dis.readUTF();
File file = new File("C:/test/" + loadingFile);
FileInputStream fis = new FileInputStream(file);
DataInputStream fsis = new DataInputStream(fis);
byte[] filecontants = new byte[(int)file.length()];
fsis.readFully(filecontants);
dos.writeLong(filecontants.length);
dos.write(filecontants);
dos.flush();
}
} catch(Exception e){
continue;
}
}
} catch (Exception e) {
System.out.println("연결 오류");
}
}
}
안녕하세요, 파일 전송 관련해서 과제 중인데요, 혹시 파일을 여러 개 보내려면 어떻게 해야할까요? 조언 얻고 싶습니다. 감사합니다!