TIL(Today I Learned)_230802

Aspyn Choi·2023년 8월 2일
0

TIL

목록 보기
15/37

☝🏻오늘 배운 것

1. 입출력(IO == input/output)

- 입력 / 출력

  1. 입력 : 외부(키보드)에서 내부(프로그램)로 값(파일)이 들어오는 것 == 파일을 읽는 것
  2. 출력 : 내부(프로그램)에서 외부(모니터/콘솔창)로 값이 나가는 것 == 파일 쓰기/내보내기

-> 입출력 : 내부와 외부 사이에서 값들이 왔다갔다하는 것, 외부와 내부를 연결해주는 통로(스트림 Stream)이 필요함

  1. 스트림 : 내부와 외부를 연결해주는 통로. 한방향으로만 흐름

- 스트림(Stream) 클래스

: 입출력 장치에서 데이터를 읽고 쓰기 위해서 자바에서 제공하는 클래스
: 모든 스트림은 단방향이며 각각의 장치마다 연결할 수 있는 스트림 존재
: 하나의 스트림으로 입출력을 동시에 수행할 수 없으므로 동시에 수행하려면 2개의 스트림 필요

-바이트기반 : 문자, 그림, 영상 등 다양한 데이터를 전달 가능(1byte로 읽고 4byte로 반환)
-문자기반 : only 문자만 전달 가능 (2byte로 읽고 4byte로 반환)

- File 클래스

: 파일 시스템의 파일을 표현하는 클래스
: 파일 크기, 파일 속성, 파일 이름 등의 정보와 파일 생성 및 삭제 기능을 제공함

- FileInputStream

: 파일을 바이트 단위로 읽을 때 사용
: 그림, 오디오, 비디오, 텍스트 파일 등 모든 종류의 파일 읽기 가능
: InputStream의 하위 클래스임

- FileOutputStream

: 파일능 바이트 단위로 저장할 때 사용
: 그림, 오디오, 비디오, 텍스트 파일 등 모든 종류의 데이터를 파일로 저장
: OutputStream의 하위 클래스임

- FileReader

: 문자 단위로 텍스트 기반 파일을 읽을 때 사용
: 텍스트가 아닌 그림, 오디오, 비디오 등의 파일은 읽기 불가능
: Reader의 하위 클래스

- FileWriter

: 문자 단위로 텍스트 기반 파일을 쓸(저장할) 때 사용
: 텍스트가 아닌 그림, 오디오, 비디오 등의 파일은 저장 불가능
: Writer의 하위 클래스

2. 입출력 예제

package edu.kh.io.model.service;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class IOService {
	
	// IO
	
	// Input(입력) : 외부에서 내부로 데이터를 들여오는 것
	// Output(출력) : 내부에서 외부로 데이터를 내보내는 것
	
	// Stream : 입/출력의 통로 역할(데이터가 흘러가는 통로)
	//			기본적으로 Stream은 단방향이다.
	
	
	// 1) 파일출력(내부 == 프로그램, 외부 == 파일) /바이트 기반 스트림
	public void output1() {
		
		// 바이트 기반 스트림 이용
		FileOutputStream fos = null;
		
		// FileOutputStream 객체 생성 시 
		// FileNotFoundException / IOException 예외가 발생할 가능성이 있음 
		// -> IOException이 상위클래스라서 IOException만 캐치문으로 잡아줌
		
		
		try {
			
			fos = new FileOutputStream("test1.txt");
			// 현재 프로그램에서 test1.txt파일로 출력하는 통로 객체 생성
			
			// 파일에 "Hello" 내보내기
			String str = "Hello";
			
			for(int i = 0; i < str.length(); i++) {
				
				// Hello를 한 문자씩 끊어서 파일로 출력하기
				fos.write(str.charAt(i));
				
				// wirte()는 IOException을 발생시킬 가능성이 있다.
				
			}
			
		}catch(IOException e) {
			System.out.println("예외 발생");
			e.printStackTrace(); // 예외추척
			
		} finally {
			// 예외가 발생 하든 말든 무조건 수행
			
			// 사용한 Stream ""자원을 반환""(통로 없애기) --> 필수 작성!!
			// 프로그램 메모리 관리차원에서 항상 다쓰면 끊어줘야함
			// 작성하지 않으면 문제점으로 꼽을 수 있다.
			
			try {
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}
	
	// 파일 출력 (문자 기반 스트림)
	public void output2() {

		FileWriter fw = null;
		// 프로그램 -> 파일로 쓰는 문자 기반 스트림
		
		try {
			
			fw = new FileWriter("test1.txt"); // 외부 파일과 연결하는 스트림 객체 생성
			
			String str = "안녕하세요. Hello. 1234 !@#";
			
			fw.write(str);
			// 실행했는데 출력이 안되고있다.
			// --> 한 줄을 통째로 보내기위해서 "버퍼"를 이용하는데
			// --> 아직 버퍼에 담겨있음 이걸 강제로 밀어서 버퍼를 비워야함
			
			// close()구문을 수행하면 통로에 남아있는 내용을 모두 내보내고
			// 통로를 없앤다!
			
			
		}catch(IOException e) {
			e.printStackTrace();
			
		}finally {
			
			try {
				fw.close();
			}catch(IOException e){
				e.printStackTrace();
			}
			
		}
		

	}
	
	// 3) 파일 입력 : 외부(파일) -> 내부(프로그램)으로 읽어오기
	// 바이트 기반 스트림
	public void input1() {
		
		FileInputStream fis = null;
		// 파일 -> 프로그램으로 읽어오는 바이느 기반 스트림
		
		try {
			
			fis = new FileInputStream("test1.txt");
			
			// FileInputStream 은 1byte 씩만 읽어올 수 있다.
			
			while(true) {
				
				int data = fis.read(); // 다음 1byte를 읽어오는데 정수형임
										// 다음 내용이 없으면 -1 반환
				
				if(data == -1) { // 다음 내용 없음 -> 종료
					break;
				}
				
				// 반복 종료가 안됐으면 char로 강제 형변환 하여 문자로 출력
				System.out.print( (char)data );
				
			}
			
		}catch(IOException e) {
			e.printStackTrace();
			
		}finally {
			
			try {
				fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}
	
	// 4) 파일 입력 (문자 기반 스트림)
	public void input2() {
		
		FileReader fr = null;
		
		try {
			
			fr = new FileReader("test1.txt"); //파일로부터 읽어오는 통로 객체 생성
			
			while(true) {
				
				int data = fr.read(); // 다음 한 문자를 읽어옴. 없으면 -1 반환
				
				if(data == -1) {
					break;
				}
				
				System.out.print( (char)data );
			}
			
		}catch(IOException e) {
			e.printStackTrace();
			
		}finally {
			
			try {
				fr.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}
		
}

3. 네트워크

- 네트워크란?

: 여러 대의 컴퓨터를 통신 회선으로 연결한 것(홈 네트워크, 지역 네트워크, 인터넷 등이 해당)
: 여러 통신기기들을 서로 연결하여 데이터를 손쉽게 주고받거나 자원 등을 공유하기 위해 사용

- 서버와 클라이언트

: 서버 -> 서비스를 제공하는 사람(프로그램 또는 컴퓨터)
: 클라이언트 -> 서비스를 요청하여 제공받아 사용하는 사람(프로그램 또는 컴퓨터)
: 서버와 클라이언트 -> 네트워크로 연결된 컴퓨터간의 관계를 역할(role)로 구분한 개념
: 서버는 서비스를 제공하는 프로그램으로 클라이언트의 연결을 수락하고 요청 내용을 처리 후 응답을 보내는 역할
: 클라이언트는 서비스를 받는 프로그램으로 네트워크 데이터를 필요로 하는 모든 어플리케이션이 해당 됨

- IP주소(Internet Protocol)

: 네트워크 상에서 컴퓨터를 식별하는 번호(통신규약)로 네트워크 어댑터(랜카드)마다 할당 되어 있음

- 포트(Port)

: 같은 컴퓨터 내에서 프로그램을 식별하는 번호
: 클라이언트는 서버 연결 요청 시 IP주소와 포트 번호를 알아야 함
: 포트 번호는 1~65535의 번호만 사용할 수 있음

- 소켓 프로그래밍

  1. 소켓프로그래밍?
    : 소켓을 이용한 통신 프로그래밍

  2. 소켓(Socket)
    : 프로세스 간의 통신에 사용되는 양쪽 끝 단

  3. 프로토콜(Protocol)
    : 컴퓨터 간의 정보를 주고 받을 때의 통신방법에 대한 규약(제약에 가까움)으로 접속이나, 전달방식, 데이터의 형식, 검증 방법 등을 맞추기 위한 약속

  4. TCP(Transmission Control Protocol)
    : 데이터의 전달의 신뢰성을 최대한 보장하기 위한 방식으로 연결지향형 통신이다.
    : 순차적으로 데이터를 전송하고 확인 및 오류 시 재전송을 한다.
    : 전세계적으로 가장 많이 사용하는 통신

  5. UDP(User Datagram Protocol)
    : 데이터의 빠른 전달을 보장하기위한 방식으로 비연결 지향형 통신이다. 확인 및 재전송 작업이 없다.

- TCP 소켓 프로그래밍

: 클라이언트와 서버간의 1:1 소켓 통신
: 서버가 먼저 실행 되어 클라이언트의 요청을 기다려야 하고 서버용 프로그램과 클라이언트용 프로그램을 따로 구현해야 함
: 자바에서는 TCP 소켓 프로그래밍을 위해 java.net패키지에서 ServerSocket과 Socket클래스 제공

- 서버용 TCP 소켓 프로그래밍 순서

- 클라이언트용 TCP 소켓 프로그래밍 순서

- TCP 소켓 프로그래밍 해보기

✅ Sever

package edu.kh.network.model.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TCPServer {
	
	// Server : 서비스를 제공하는 프로그램 또는 컴퓨터
	// Client : 서버에 서비스를 요청하여 사용하는 프로그램 또는 컴퓨터
	
	// TCP socket 프로그래밍
	
	// TCP : 데이터 전달의 신뢰성을 최대한 보장하기 위한 방식(연결 지향형 통신)
	//		순차적으로 데이터를 전달하고 확인 및 오류 시 재전송
	
	// Socket : 프로세스의 통신에 사용되는 양쪽 끝단.
	//			서버와 크라이언트가 통신을 하기위한 매개체
	
	// ServerSocket : 서버용 소켓
	// - Port와 연결되어 외부 요청을 기다리는 역할
	// -> 클라이언트 요청이 올 경우 이를 수락하고, 클라이언트가 사용할 수 있는 소켓을 생성
	// --> 서버소켓과 클라이언트 소켓이 연결되어 데이터 통신이 가능해짐.
	
	public void serverStart() {
		
//		1. 서버의 포트번호 정함
		int port = 8500; // port번호는 0~65535 사이 지정 가능
						// 단, 1023번 이하는 이미 사용중인 경우가 많으니 제외
		
		/* 사용할 변수 미리 선언 */
		
		ServerSocket serverSocket = null; // 서버 소켓 저장 변수
		Socket clientSocket = null; // 클라이언트 소켓 저장 변수
		
		InputStream is = null; // 클라이언트 -> 서버 입력용 스트림 변수
		BufferedReader br = null; // 입력용 보조 스트림 변수
		
		OutputStream os = null; // 서버 -> 클라이언트 출력용 스트림 변수
		PrintWriter pw = null; // 출력용 보조 스트림 변수
		
		try {
			
//			2. 서버용 소켓 객체 생성
			serverSocket = new ServerSocket(port); // 서버용 소켓을 생성하여 포트 결합
			
//			3. 클라이언트 쪽에서 접속 요청이 오길 기다림
			// - 서버용 소켓은 생성되고나면 클라이언트 요청이 오기 전까지 
			// 	 다음코드 수행하지않고 대기하고 있음.
			System.out.println("[Server]");
			System.out.println("클라이언트의 요청을 기다리고 있습니다.");
			
//			4. 접속 요청이 오면 요청 수락 후 해당 클라이언트에 대한 소켓 객체 생성
			// -> 요청을 수락하면 자동으로 Socket 객체가 얻어와짐
			clientSocket = serverSocket.accept();
			
			// 접속한 클라이언트의 IP를 얻어와 출력
			String clientIP = clientSocket.getInetAddress().getHostAddress();
			System.out.println(clientIP + "가 연결을 요청함...");
			
//			5. 연결된 클라이언트와 입출력 스트림 생성
			is = clientSocket.getInputStream();
			os = clientSocket.getOutputStream();
			
//			6. 보조 스트림을 통해 성능 개선
			br = new BufferedReader( new InputStreamReader(is) );
			// InputStreamReader : 문자기반 스트림과 바이트기반 스트림의 연결에 사용되는 스트림
			pw = new PrintWriter(os);
			
//			7. 스트림을 통해 읽고 쓰기
			// 7-1) 서버 -> 클라이언트에게 출력(메세지 전송)
			
			Date now = new Date(); // 생성된 시간을 기록하고있는 시간관련 객체
			// -> 날짜 출력 형식 변경이 필요함
			
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			
			String time = sdf.format(now); // now에 저장된 시간 포맷을 변경
			
			pw.println(time + "[서버 접속 성공]");
			pw.flush(); // 스트림에 있는 내용을 모두 밀어냄.
			
			// 7-2) 클라이언트 -> 서버에게 입력(메세지 전송 받기)
			String message = br.readLine(); //클라이언트 메세지 한줄 읽어옴
			
			System.out.println(clientIP + "가 보낸 메세지 : " + message);
			
		}catch(IOException e){
			e.printStackTrace();
			
		}finally {
//			8. 통신 종료
			
			// 사용한 스트림, 소켓 자원 모두 반환(close)
			
			try {
				// 보조스트림 close시 연결된 기반스트림(is, os)도 같이 close됨
				if(pw != null) pw.close();
				if(br != null) br.close();
				
				if(serverSocket != null) serverSocket.close();
				if(clientSocket != null) clientSocket.close();
				
			}catch(IOException e) {
				e.printStackTrace();
			}
		}	
	}
	

}

✅ Client

package edu.kh.network.model.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class TCPClient {
	
	public void clientStart() {
		
		//	1. 서버의 IP주소와 서버가 정한 포트번호를 매개변수로 하여 클라이언트용 소켓 객체 생성
		String serverIP = "127.0.0.1"; // loop back ip(내 컴퓨터를 가리키는 ip주소)
		int port = 8500; // 서버소켓이 기다리고있는 포트 번호
		
		// *필요한 변수 선언 *
		Socket clientSocket = null; // 서버와 연결할 클라이언트용 소켓을 저장할 변수
		
		BufferedReader br = null; // 서버 -> 클라이언트로 읽어오는 보조 스트림
		PrintWriter pw = null; // 클라이언트 -> 서버로 출력하는 보조 스트림
		
		try {
			//	2. 서버와의 입출력 스트림 오픈 -> 먼저 소켓이 필요함
			System.out.println("[Client]");
			
			clientSocket = new Socket(serverIP, port);
			//	3. 보조 스트림을 통해 성능 개선
			br = new BufferedReader( new InputStreamReader(clientSocket.getInputStream() ) );
			pw = new PrintWriter( clientSocket.getOutputStream() );
			
			//	4. 스트림을 통해 읽고 쓰기
			// 4-1) 서버 접속 성공 시
			// 		서버가 출력한 "[서버 접속 성공]" 메세지 읽어오기
			
			String message = br.readLine();
			System.out.println("서버로부터 받은 메세지 : " + message);
			
			// 4-2) 클라이언트 -> 서버로 메세지 전송
			Scanner sc = new Scanner(System.in);
			System.out.print("입력 : ");
			String input = sc.nextLine();
			
			pw.println(input);
			pw.flush();
			
		}catch(Exception e) {
			e.printStackTrace();
			
		}finally {
			//	5. 통신 종료
			
			try {
				
				if(pw != null) pw.close();
				if(br != null) br.close();
				if(clientSocket != null) clientSocket.close();
				
			}catch(IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}
	

}

1개의 댓글

comment-user-thumbnail
2023년 8월 2일

잘 봤습니다. 좋은 글 감사합니다.

답글 달기