본문 바로가기

Java 웹 개발

21.09.16 - 웹 개발 입문 27일차

파일입출력 - 문자열 출력

문자열은 객체 출력, 멀티바이트 출력, 싱글바이트 출력 모두 가능하다.

하지만 객체, 멀티바이트는 안쓴다 -> 싱글바이트 사용

 

싱글바이트

FileWriter를 사용한 문자열 출력
1. 버퍼의 크기를 변경할 수 있는가?
 --> BufferedWriter 사용
2. 한줄단위 출력 또는 다른 유형의 데이터도 문자열로 출력?
--> PrintWriter 사용

package api.io.string;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class Test04 {
	public static void main(String[] args) throws IOException {

		File target = new File("sample", "string.txt");
		FileWriter out = new FileWriter(target);

		out.write("안녕 Java!");
		out.write("\n");
		out.write("안녕 Java!");
		out.write("\n");
		out.write("안녕 Java!");
		out.write("\n");

		int a = 100;
//		out.write(a);
//		out.write("100");
		out.write(String.valueOf(a));

//		out.flush();
		out.close();
	}
}

 

필요한 Writer들을 조합하여 사용
(System.out 도 PrintWriter 형태의 객체이다.)

package api.io.string;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class Test05 {
	public static void main(String[] args) throws IOException {

		File target = new File("Sample", "string.txt");
		FileWriter out = new FileWriter(target);
		BufferedWriter buffer = new BufferedWriter(out, 8192);// 외장버퍼
		PrintWriter printer = new PrintWriter(buffer);// 출력도우미

		// [프로그램] → printer → buffer → out → target → [string.txt]

		// write가 아니라 print 계열의 명령으로 출력을 할 수 있도록 지원
		printer.println("안녕 Java!");
		printer.println("안녕 Java!");
		printer.println("안녕 Java!");

		int a = 100;
		printer.println(a);

//		printer.flush();
		printer.close();

	}
}

안녕 Java!
안녕 Java!
안녕 Java!
100

 

 

 

Q. 사용자에게 문자열을 지속적으로 입력받아 `sample/user.txt` 파일에 저장하는 프로그램을 구현
사용자가 `종료`라고 입력하면 프로그램을 종료하도록 처리

package api.io.string;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;

public class Test06_1 {
	public static void main(String[] args) throws IOException {

		Scanner sc = new Scanner(System.in);

		File target = new File("sample", "user.txt");
		FileWriter out = new FileWriter(target);
		BufferedWriter buffer = new BufferedWriter(out);
		PrintWriter printer = new PrintWriter(buffer);

		// [키보드] → System.in → sc → [프로그램] → printer → buffer → out → target → [user.kh]

		while (true) {
			System.out.print("입력 : ");
			String line = sc.nextLine();
			if (line.equals("종료"))
				break;
			printer.println(line);
			printer.flush();
		}

		sc.close();
		printer.close();

		System.out.println("저장이 완료되었습니다");
	}
}

입력 : 헬로우
입력 : hello
입력 : 1234
입력 : 종료
저장이 완료되었습니다

 

헬로우
hello
1234

 

- 임시 파일 만드는법

package api.io.string;

import java.io.File;
import java.io.IOException;

public class Test06_2 {
	public static void main(String[] args) throws IOException {

		// 임시파일 생성
		File dir = new File("sample");
		File tempFile = File.createTempFile("temp-", ".txt", dir);

		// 임시 파일은 예약 삭제를 설정
		tempFile.deleteOnExit();

	}
}

 

 

문자열 입력

글자 수를 정해서 입력받는것이 아니라 줄 단위로 입력받도록 도구를 조합
줄 단위라 함은 개행문자(\n)를 발견하기 전까지라고 볼 수 있다.

package api.io.string;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Test08_1 {
	public static void main(String[] args) throws IOException {

		File target = new File("sample", "string.txt");
		FileReader in = new FileReader(target);
		BufferedReader buffer = new BufferedReader(in);

		// BufferedReader에는 read() 말고 readLine() 이라는 명령이 있다.
		// (주의) EOF == null 이다
		while (true) {
			String line = buffer.readLine();
			if (line == null)
				break;
			System.out.println("line = " + line);
		}

		buffer.close();
	}
}

line = 안녕 Java!
line = 안녕 Java!
line = 안녕 Java!
line = 100

 

 

 

네트워크 - 기본 개념 및 포트스캔

# 네트워크 프로그래밍


네트워크 연결이 되어 있다는 전제 하에 다른 대상과 데이터를 주고받는 프로그램을 구현하는 것

- 기반지식
- 네트워크 구성에 대한 이해(IP, Port, Protocol)
- 쓰레드(Thread)에 대한 이해
- 스트림(Stream)에 대한 이해
- 데이터의 종류
- 싱글바이트
- 멀티바이트
- 객체
- 문자열

## 통신 방식에 따른 구분

- 연결형 통신 : TCP
- 소켓(Socket) : 생성된 연결
- 클라이언트(Client) : 연결을 시도하는 주체
- 서버(Server) : 연결을 수락하는 주체
- IP : 연결 생성을 위한 네트워크상에서의 PC 식별정보
- Port : 연결 생성을 위한 PC 내에서의 프로그램 식별정보
- 비연결형 통신 : UDP
- 전송자(Sender) : 데이터를 보내는 주체
- 수신자(Receiver) : 데이터를 받는 주체
- 유니캐스트(Unicast) : 일대일 메세지 전송 방식
- 멀티캐스트(Multicast) : 특정 채널에 소속된 대상에게만 메세지를 보내는 방식(ex : 카톡 그룹채팅)
- 브로드캐스트(Broadcast) : 전체에게 메세지를 보내는 방식(ex : 공지사항, 방송)

 

 

 

Server

TCP 서버에서 필요한 코드를 분석
= 음식점과 같은 가게의 역할과 비슷하다.
= 가게 문을 열고 손님을 받을 준비를 해야 한다.
= 가게 문을 연다는 것은 프로그램을 구동시킨다는 것을 의미
= 프로그램은 구동되려면 반드시 포트를 설정해야 한다.

= 포트의 범위는 0 부터 65535 까지이다.
= (중요) 하나의 포트에는 하나의 프로그램만 구동할 수 있다.

 

 

내 컴퓨터에서 사용하는 포트 확인하는 프로그램(포트스캐너)
= 0부터 65535까지 다 열어보면 된다.

package api.net.tcp01;

import java.io.IOException;
import java.net.ServerSocket;

public class Server2 {
	public static void main(String[] args) {

		for (int i = 0; i <= 65535; i++) {
			try {
				ServerSocket server = new ServerSocket(i);
				// System.out.println("사용 가능한 번호입니다");
			} catch (IOException e) {
				System.out.println("[" + i + "] 이미 사용중인 번호입니다");
			}
		}

	}
}

 

 

네트워크 - 서버 준비코드

= 서버를 30000번(안쓰는포트) 포트에서 구동되도록 생성
= 사용자가 접속할 때까지 기다린 뒤 접속 정보를 socket 형태로 관리
= socket에는 다음 정보가 필요하다
1. 접속한 클라이언트의 공인IP주소
2. 접속한 클라이언트 프로그램의 Port번호
3. 서버의 Port번호
= 다 사용한 자원들을 정리

package api.net.tcp01;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server3 {
	public static void main(String[] args) throws IOException {

//		서버를 30000번 포트에서 구동되도록 생성
		ServerSocket server = new ServerSocket(30000);
		System.out.println("서버가 구동되었습니다");

//		사용자가 접속할 때까지 기다린 뒤 접속 정보를 socket 형태로 관리
		Socket socket = server.accept();
		System.out.println("서버에 클라이언트가 접속했습니다");

//		socket에는 다음 정보가 필요하다
//		1. 접속한 클라이언트의 공인IP주소
//		2.접속한 클라이언트 프로그램의 Port번호
//		3. 서버의 Port번호
		System.out.println("소켓 정보 : " + socket.toString());

//		데이터를 주고받는 코드

//		다 사용한 자원들을 정리
		socket.close();// 사용자 1명과의 연결을 종료
		System.out.println("사용자와의 연결을 종료하였습니다");

		server.close();// 서버를 중지
		System.out.println("서버를 중지하였습니다");
	}
}

 

 

네트워크 - 클라이언트 소켓 생성

Client

TCP 클라이언트에서 필요한코드
=클라이언트는 음식점에 비유하면 손님과 같은 역할을 수행
=손님은 가게가 문을 열면 전화를 걸어서 음식을 주문할 수 있다.
= 전화를 거는 행위는 소켓을 생성한다고 볼 수 있다.
= 전화를 걸기 위해서는전화번호가 필요한 것처럼 소켓을 생성하려면 대상 프로그램의 위치정보가 필요하다
= IPv4정보와 Port정보가 필요하다.

package api.net.tcp01;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
	public static void main(String[] args) {

//		Socket Socket = new Socket(IP주소, Port번호);
		try {
			Socket socket = new Socket("ip", 30000);// 127.0.0.1은 IP계의 this
			// Plan A : 정상적으로 연결이 수행된 경우
			System.out.println("연결 성공했습니다");
		} catch (Exception e) {
			// Plan B : 어떠한 원인에 의해 연결이 수행되지 않은 경우
			System.out.println("연결이 실패했습니다");
			e.printStackTrace();
		}

	}
}

 

네트워크 - 클라이언트 준비코드

package api.net.tcp01;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client2 {
	public static void main(String[] args) throws UnknownHostException, IOException {

			Socket socket = new Socket("ip", 30000);
			System.out.println("연결 성공했습니다");
			
			System.out.println("소켓 정보 : "+socket);
			
			//데이터를 주고받는 코드
			
			//연결 종료
			socket.close();
			System.out.println("서버와의 연결이 종료되었습니다");

		}
}

 

 

네트워크 - 바이트 전송 예제

Client에게 byte 5개를 전달하는 코드

= socket.getOutputStream()을 활용하여 출력

package api.net.tcp02;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
	public static void main(String[] args) throws IOException {

		ServerSocket server = new ServerSocket(30000);
		Socket socket = server.accept();
        
		OutputStream out = socket.getOutputStream();

		out.write(104);
		out.write(101);
		out.write(108);
		out.write(108);
		out.write(111);

		socket.close();
		server.close();
	}
}

 

Server에서 전송되는 byte 5개를 수신하는 코드
= socket.getInputStream()을 활용하여 입력

package api.net.tcp02;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
	public static void main(String[] args) throws UnknownHostException, IOException {

//		Socket socket= new Socket("127.0.0.1", 30000);
		Socket socket = new Socket("localhost", 30000);

		InputStream in = socket.getInputStream();

		int a = in.read();
		int b = in.read();
		int c = in.read();
		int d = in.read();
		int e = in.read();

		socket.close();

		System.out.println(a);
		System.out.println(b);
		System.out.println(c);
		System.out.println(d);
		System.out.println(e);

	}
}

104
101
108
108
111

 

 

Q. 서버에서는 특정 파일을 접속자에게 배포하도록 구성되어 있습니다.
- 서버의 주소 : ip
- 서버의 포트 : 30000
`Client` 클래스를 만든 뒤, 서버에 접속하여 배포하는 파일을 받아 `lion.gif`라는 이름으로 저장하도록 프로그램을 구현

package api.net.tcp03;

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) {

		// 파일을 먼저 다 불러와놓고 사용자 접속 시 전송하도록 구현
		// = 접속할 때마다 불러오는것보다 성능이 탁월하게 좋음

		File target = new File("image", "lion.gif");
		byte[] buffer = new byte[(int) target.length()];
		try (FileInputStream in = new FileInputStream(target);) {
			in.read(buffer);
		} catch (Exception e) {
			System.err.println("이미지 로딩 실패");
			System.exit(-1);
		}

		while (true) {
			try (ServerSocket server = new ServerSocket(30000);) {
				System.out.println("서버 구동 시작");
				while (true) {
					try (Socket socket = server.accept();) {
						System.out.println("사용자 접속 : " + socket.getInetAddress().getHostAddress());
						socket.getOutputStream().write(buffer);
						System.out.println("--> 이미지 전송 완료");
					}
				}
			} catch (Exception e) {
//				e.printStackTrace();
				System.err.println("--> 에러 발생");
			}
		}

	}
}

 

package api.net.tcp03;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client3 {
	public static void main(String[] args) throws UnknownHostException, IOException {
		// 서버에 접속해서 전송되는 이미지를 다운로드받아 `download/lion.gif`로 저장
		// = TCP 연결
		// = 파일 출력(싱글바이트)

		Socket socket = new Socket("ip", 30000);

		// 파일을 내려받는 코드
		// = 버퍼의 크기를 8192 byte로 정하고 수신하여 저장
		InputStream in = socket.getInputStream();
		BufferedInputStream buffer = new BufferedInputStream(in, 8192);
		byte[] data = new byte[8192];

		File dir = new File("download");
		dir.mkdirs();
		File target = new File(dir, "lion.gif");
		OutputStream out = new FileOutputStream(target);

		while (true) {
			int size = buffer.read(data);
			if (size == -1)
				break;
			// 파일 출력 코드
			// System.out.println("size = " + size);
			out.write(data, 0, size);
		}

		socket.close();
		out.close();
	}
}

 

 

 

- 과제

클라이언트가 접속하면 접속한 클라이언트에게 이번주 로또번호 6개를 전송하는 서버를 구현
클라이언트는 서버가 전송하는 로또번호를 받아서 화면에 출력하도록 구현
접속할 때마다 다른 번호가 오도록 프로그래밍 하세요

package api.net.tcp04;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

public class Server {
	public static void main(String[] args) throws IOException {

		ServerSocket server = new ServerSocket(30000);
		System.out.println("로또 프로그램 시작");

		while (true) {
			Socket socket = server.accept();
			System.out.println("로또 번호 전송 완료");
			OutputStream out = socket.getOutputStream();

			Random r = new Random();
			Set<Integer> lotto = new TreeSet<>();
			
			while (lotto.size() < 6) {
				int number = r.nextInt(45) + 1;
				lotto.add(number);
			}
			for (int number : lotto) {
				out.write(number);
			}
			socket.close();
		}

	}
}

 

package api.net.tcp04;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Set;
import java.util.TreeSet;

public class Client {
	public static void main(String[] args) throws IOException {

		Socket socket = new Socket("localhost", 30000);
		InputStream in = socket.getInputStream();

		Set<Integer> lotto = new TreeSet<>();
		while (true) {
			int number = in.read();
			if (number == -1)
				break;
			lotto.add(number);
		}
		System.out.println("이번주 로또번호는?-->" + lotto);

		socket.close();
		in.close();
	}
}