Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
Tags
- 인텔리제이 한글 깨짐 해결법
- break문
- 연관관계
- multi-threading
- JAVA기초
- IntelliJ IDEA
- function
- 생성자
- 형 변환
- java변수
- 집합관계
- 컴파일
- JAVA객체지향
- 상수
- Thread
- this예약어
- While
- 반복문
- 자바 멀티스레딩
- 메서드 오버로딩
- for문
- 메서드
- Java
- 포함관계
- 인텔리제이 기초 설정
- continue문
- 시스템 환경 변수 편집
- OPP개념
- 접근제어지시자
- Java데이터 타입
Archives
- Today
- Total
최원종의 개발 블로그
(소켓 - 7) 소켓을 활용한 파일 전송 (1:1) 본문
채팅에서 파일 전송 하기
//지금까지 한 것
소켓-2~6 : [프로그램] ──문자열──► [프로그램]
//진행할 내용
소켓-7 : [프로그램] ──파일──► [프로그램]
파일 전송 순서
1. 파일 이름 (서버가 어떤 이름으로 저장할지 알아야 함)
2. 파일 내용 (실제 데이터)
로컬 파일 복사 방법
// 로컬 파일 복사
FileInputStream fis = new FileInputStream("원본.zip");
FileOutputStream fos = new FileOutputStream("복사본.zip");
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
파일 전송 방법
// 소켓-7 - 네트워크로 파일 전송
FileInputStream fis = new FileInputStream("보낼파일.zip");
OutputStream out = socket.getOutputStream(); // 파일 대신 네트워크로
// 4096 크기는 내가 임의로 정한 크기 입니다. 4096 = 2의 12승 = 4KB
// 하지만 사전 기반 지식으로 운영체제가 디스크에서 데이터를 읽을 때 보통 4KB 단위로 처리합니다.
// 버퍼 크기를 4KB 로 맞추면 운영체제 처리 단위와 딱 맞아서 효율적입니다.
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead); // 파일에 쓰는 대신 네트워크로 전송
}
파일 복사: FileInputStream → FileOutputStream (로컬 → 로컬)
소켓-7 파일 전송: FileInputStream → socket.getOutputStream() (로컬 → 네트워크)
socket.getInputStream() → FileOutputStream (네트워크 → 로컬)
파일 이름을 먼저 보내는 이유 (프로토콜(약속))
//서버가 파일을 받기 전에 파일 이름을 알아야 저장할 수 있다.
//(나에게 파일을 보낼려면 약속을 먼저 지켜 파일 이름 보내고 다음에 파일데이터를 보내)
클라이언트가 보내는 순서:
1단계: [파일 이름] - 고정 100바이트
"employees.zip" + 빈 공간(나머지는 0)
[e][m][p]...[p][0][0]...[0]
← 13바이트 이름 →← 87바이트 빈 공간 →
2단계: [파일 내용] - 실제 파일 데이터
[바이트 1][바이트 2]...[파일 끝]
고정 100바이트 사용 이유
소켓은 바이트 스트림을 연속으로 전송합니다.
파일 이름과 파일 내용이 붙어서 오면
서버가 어디까지가 이름이고 어디서부터 내용인지 구분할 수 없습니다.
고정 100바이트로 정해두면:
서버가 정확히 100바이트를 이름으로 읽고
그 다음부터는 파일 내용으로 처리
이처럼 서버와 클라이언트가 데이터 형식을 미리 약속하는 것을 프로토콜이라고 합니다.
파일 서버측 코드
package server.ch05;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleFileServer {
private static final int PORT = 5000;
private static final String UPLOAD_DIR = "Uploads/";
public static void main(String[] args) {
//실행에 흐름 처리
//먼저 저장 폴더 생성하는 법
new File(UPLOAD_DIR).mkdir();// 저장 폴더 생성
System.out.println("파일 서버 시작 - 포트 : " + PORT);
try (ServerSocket serverSocket = new ServerSocket(PORT);
Socket clientSocket = serverSocket.accept() // 블로킹 상태
) {
System.out.println("클라이언트 연결 됨");
handleClient(clientSocket);
} catch (IOException e) {
throw new RuntimeException(e);
}
}//end of main
//파일 처리 기능 함수
private static void handleClient(Socket socket) {
try (
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream()
) {
//1단계 : 파일 이름 수신 ( 고정 100바이트)
byte[] nameBuffer = new byte[100];
in.read(nameBuffer);//한 번에 100바이트 읽기
//이 다음부터 아래에서 다시 in.read() 는 파일 내용을 읽음
//[a][b][c][.][t][x][t][0][0][0]....
String fileName = new String(nameBuffer).trim();
//trim(): 뒤에 붙은 빈 공간(0바이트)제거
System.out.println("수신할 파일 이름 : " + fileName);
//2단계: 파일 내용 수신 후 서버측 컴퓨터 저장
File file = new File(UPLOAD_DIR + fileName);
try (FileOutputStream fos = new FileOutputStream(file)) {
//클라이언트가 보낸 데이터를 읽어서 서버측 컴퓨터에 저장해야 함.
byte[] buffer = new byte[4096];//크기 선언
int bytesRead;//배열 담을 변수
while ((bytesRead = in.read(buffer)) != -1) { //4kb만큼 담기
fos.write(buffer, 0, bytesRead);//읽은 만큼만 저장
}
}
System.out.println("파일 저장 완료 : " + UPLOAD_DIR + fileName);
//클라이언트 측에 완료 메세지 전송
out.write(("파일 업로드 성공 : " + fileName).getBytes());
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}//end of class
-클라이언트 측 코드
package client.ch06;
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class SimpleFileClient {
private static final int PORT = 5000;
public static void main(String[] args) {
System.out.println("파일 전송 클라이언트 시작");
Scanner sc = new Scanner(System.in);
System.out.println("전송할 파일 경로를 입력하세요(예 :C:\\_work_Java\\test.txt)");
String filePath = sc.nextLine();
File file = new File(filePath);
if (!file.exists() || !file.isFile()) {
System.out.println("파일이 존재하지 않습니다");
return;
}
try (Socket socket = new Socket("localhost", PORT)) {
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
//1단계: 파일 이름 전송 ( 고정 100바이트)
//C:/test.txt --> file.getName() --? test.txt 파싱했다
String fileName = file.getName();
byte[] nameBytes = fileName.getBytes();
byte[] nameBuffer = new byte[100]; // 100바이트 선언
//방어적 코드 - 파일 이름이 100바이트 이상 안되게처리
if (nameBytes.length > 100) {
System.out.println("파일 이름이 너무 깁니다.(최대 100자)");
return; //코드가 더 안내려가게 반환
}
//파일 이름 전송
for (int i = 0; i < nameBytes.length; i++) {
nameBuffer[i] = nameBytes[i];
}
//서버측에서 딱 한 번 100바이트 통으로 읽기 위한 코드로 작성되어 있음
out.write(nameBuffer);
out.flush();
//2단계 파일 내용 전송
try (FileInputStream fis = new FileInputStream(file)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
out.flush();
}
System.out.println("전송 완료 : " + fileName);
//3단계 서버측 응답 수신
byte[] responseBuffer = new byte[1024];
int responseLength = in.read(responseBuffer);
if (responseLength > 0) {
System.out.println("서버 응답 : " + new String(responseBuffer, 0, responseLength));
}
} catch (UnknownHostException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}//end of main
}//end of class
코드 전체 흐름
클라이언트 서버
| |
new Socket(5000) ──────────────► accept()
| |
[파일 이름 100바이트] ──────────► in.read(nameBuffer) → "employees.zip"
| |
[파일 내용 4KB 씩] ──────────────► fos.write(buffer, 0, bytesRead) → 파일 저장
| |
◄─────────────────────────── "파일 업로드 성공" 응답
핵심 요약
파일 전송 = 파일 이름 먼저(100바이트) + 파일 내용 전송
프로토콜
→ 서버와 클라이언트가 데이터 형식을 미리 약속
→ 고정 100바이트 = 이름 끝을 정확히 알기 위한 약속
I/O 단원 연결
→ 18단원 FileInputStream + write(buffer, 0, bytesRead) 그대로 적용
→ FileOutputStream 자리에 socket.getOutputStream() 교체
trim()
→ 100바이트 배열 뒷부분의 빈 공간(0) 제거
'Java > JAVA 유용한 클래스' 카테고리의 다른 글
| ArrayList - 컬렉션 (0) | 2026.03.30 |
|---|---|
| 컬렉션 프레임워크(Collections Framework) (0) | 2026.03.27 |
| (소켓 - 6) 1:N 실시간 채팅 (브로드캐스트) (0) | 2026.03.27 |
| (소켓 - 5) 1:1 실시간 채팅(멀티스레드) (0) | 2026.03.27 |
| (소켓 - 4) 1: 1 양방향 통신 (0) | 2026.03.27 |