Day_21 ( Java 기초 문법 실습 - 6 )

HD.Y·2023년 11월 27일
0

한화시스템 BEYOND SW

목록 보기
20/58
post-thumbnail

오늘 배운 문법 정리

  • 다형성(Polymorphism) 이란❓

    : 다형성이란 부모-자식 상속 관계에 있는 클래스에서 상위 클래스가 동일한 메시지로
      하위 클래스들을 서로 다르게 동작시키는 객체 지향 원리이다. 다형성을 활용하면
      부모 클래스가 자식 클래스의 동작 방식을 알 수 없어도 오버라이딩을 통해 자식
      클래스로 접근할 수 있다.

    : 다형성은 여러 객체를 하나의 타입으로 관리가 가능하기 때문에, 코드 관리가 편리해
      유지보수가 용이하고, 객체를 재사용하기가 쉬워진다는 장점이 있다.

  • 제네릭(Generics) 이란❓
    : 컴파일 시 타입을 체크해주는 기능으로 객체의 타입 안정성을 높이고, 형변환의
      번거로움을 줄여준다. 따라서 타입 안정성을 높여주고, 타입 확인과 형변환을 생략할 수
      있어 코드가 간결해 진다.
      문법) List<String> list = new ArrayList<String>( );

     public class GenericMain {
         public static void main(String[] args) {
             Parents<String> parentsString = new Parents<String>("제네릭");

             Parents<Character> parentsChar = new Parents<Character>('c');

             Parents<Integer> parentsInt = new Parents<Integer>(100);

             // 제네릭을 사용하지 않은 리스트
             List integerList1 = new ArrayList();
             integerList1.add("글자");
             integerList1.add(100);

			 // 제네릭으로 타입을 Integer로 설정한 리스트
             List<Integer> integerList2 = new ArrayList<Integer>();
             //integerList2.add("글자");  // 제네릭으로 문자열 타입 저장 불가
             integerList2.add(100);

             Map<Integer, String> map = new HashMap<Integer, String>();
             map.put(0, "값1");
         }
     }
  • 스트림(Stream) 이란❓

    : 프로그램은 외부에서 데이터를 읽거나 외부로 데이터를 출력하는 작업이 빈번하게
     발생하고, 데이터는 통로를 통해서 이동하는데 이 통로를 스트림이라고 한다.
      즉, 데이터를 운반(입/출력) 하는데 사용되는 연결통로를 말한다.

    : 흔히, 우리가 파일을 닫을 때 "해당 파일은 다른 프로그램이 사용중이라 삭제할 수 없다"
      라는 경고 메시지를 본적이 있을 것이다. 바로 이것이 스트림이 열려있기 때문에 파일을
      닫을 수 없는 것이었다.

    : 스트림의 종류 ( 수업 중 사용한 것만 정리 ✅ )
      1) 바이트 기반 스트림 : InputStream / OutputStream
      2) 보조 스트림(스트림의 기능 향상) : BufferedInputStream / BufferedOutputStream
      3) 문자 기반의 파일 입출력 스트림 : FileReader / FileWriter
      4) 파일에 데이터를 입출력하는 바이트기반 스트림 :
         FileInputStream / FileOutputStream
      5) 데이터를 다양한 형식의 문자로 출력하는 기능 제공 스트림 : PrintStream


  • 💻 스트림 실습하기 💻
import java.io.*;

public class StreamMain3 {
    public static void main(String[] args) throws IOException {
        FileInputStream fileInputStream=null;
        FileOutputStream fileOutputStream=null;
        
        try {
            // 텍스트 파일 복사 
            fileInputStream = new FileInputStream("c:\\test\\test01.txt");
            fileOutputStream = new FileOutputStream("c:\\test\\test02.txt");
            
            // 그림 파일 복사
            FileInputStream fileInputStream = new FileInputStream("c:\\test\\pic01.png");
            FileOutputStream fileOutputStream = new FileOutputStream("c:\\test\\pic02.png");
			
            byte[] bytes = fileInputStream.readAllBytes();
            for(int i=0; i<bytes.length; i++) {
                fileOutputStream.write(bytes[i]);
            }
            
            // 텍스트 파일 내용 출력 (바이트 단위로 읽기 때문에 한글은 깨진다.)
            int data = 0;
            while ((data = fileInputStream.read()) != -1) {
                System.out.print((char)data);
            }
            
            // 만약, 글자 단위로 읽고 싶다면? FileReader 스트림 사용
            fileInputStream = new FileInputStream("c:\\test\\test01.txt");
            fileOutputStream = new FileOutputStream("c:\\test\\test02.txt");
            
            int data = 0;
            while ((data = fileReader.read()) != -1) {
                System.out.print((char)data);
            }             
            
        } catch (FileNotFoundException e) {
            System.out.println("그런 파일 없음");
        } catch (IOException e) {
            System.out.println("읽을 수 없음");
        } finally {
            if(fileInputStream != null) {
                fileInputStream.close();  // 스트림을 열었으면 무조건 닫아줘야 한다.
            }
            if(fileOutputStream != null) {
                fileOutputStream.close(); // 스트림을 열었으면 무조건 닫아줘야 한다.
            }
        }
    }
}

🙉 스트림을 사용하여 네트워크 프로그래밍 실습하기 🙉

  • 첫 번째
    서버와 클라이언트를 구성하고, 서버 ➡ 클라이언트로 메시지를 보내면 클라이언트에서 메시지를 입력받고, 다시 클라이언트 ➡ 서버로 메시지를 보내면 서버에서 클라이언트가 보낸 메시지를 입력받는 코드를 구현해본다.
   package day06;

   import java.io.*;
   import java.net.ServerSocket;
   import java.net.Socket;
   import java.util.Scanner;
	
   // 서버 클래스
   public class ServerTest {
       public static void main(String[] args) {
           try {
               ServerSocket serverSocket = new ServerSocket(7777);

               Socket yhd = serverSocket.accept();

               System.out.println(yhd.getInetAddress() + " 주소를 사용하는 고객이 접속하였습니다.");


               // 여기서부터 보내는 코드
               System.out.print("고객에게 보낼 메시지를 입력하세요 : ");
               Scanner sc = new Scanner(System.in);
               OutputStream cos = yhd.getOutputStream();
               PrintStream ps = new PrintStream(cos);

               String test1 = sc.nextLine();
               ps.println(test1);
               // 여기까지 보내는 코드

               System.out.println();

               // 여기서부터 받는 코드
               System.out.print("고객이 서버로 보낸 메시지입니다 : ");
               InputStream cis = yhd.getInputStream();
               InputStreamReader isr = new InputStreamReader(cis);
               BufferedReader br = new BufferedReader(isr);

               String str = br.readLine();
               System.out.println(str);
               // 여기까지 받는 코드

               serverSocket.close();
               yhd.close();

           } catch (IOException e) {
               throw new RuntimeException(e);
           }
       }
   }

   import java.io.*;
   import java.net.Socket;
   import java.util.Scanner;

   // 클라이언트 클래스
   public class ClientTest {
       public static void main(String[] args) {
           try {
               Socket yhd = new Socket("192.168.0.114", 7777);

               System.out.print("서버에서 보낸 메시지입니다 : ");
               InputStream cis = yhd.getInputStream();
               InputStreamReader isr = new InputStreamReader(cis);
               BufferedReader br = new BufferedReader(isr);

               String str = br.readLine();
               System.out.println(str);

               System.out.print("서버에 요청할 메시지를 입력하세요 : ");
               Scanner sc = new Scanner(System.in);

               OutputStream cos = yhd.getOutputStream();
               PrintStream ps = new PrintStream(cos);

               String test2 = sc.nextLine();
               ps.println(test2);

               yhd.close();

           } catch (IOException e) {
              throw new RuntimeException(e);
           }
       }
   }

  • 코드 실행 결과 : 서버 클래스를 먼저 실행시켜준 뒤 클라이언트 클래스를 실행시킨다.

  • 두 번째
    서버와 클라이언트를 구성하고, 클라이언트 ➡ 서버로 파일의 이름을 보내면 서버에서 파일의 이름을 입력받고, 해당 파일을 서버 ➡ 클라이언트로 보내준다. 클라이언트에서는 받은 파일을 원하는 폴더에 저장하는 것을 구현해 본다.
   package day06;

   import java.io.*;
   import java.net.ServerSocket;
   import java.net.Socket;
   import java.util.Scanner;
   import java.io.FileInputStream;
   import java.io.FileOutputStream;
   
   // 서버 클래스
   public class ServerFileTest {
       public static void main(String[] args) {
           try {
               ServerSocket serverSocket = new ServerSocket(9999);

               Socket yhd = serverSocket.accept();

               System.out.println(yhd.getInetAddress() + " 주소를 사용하는 고객이 접속하였습니다.");

               // 여기서부터 받는 코드
               System.out.print("고객이 서버로 보낸 메시지입니다 : ");
               InputStream cis = yhd.getInputStream();
               InputStreamReader isr = new InputStreamReader(cis);
               BufferedReader br = new BufferedReader(isr);

               String str = br.readLine();  // str : 고객이 입력한 파일명
               System.out.println(str);
               // 여기까지 받는 코드

               System.out.println();

               // 여기서부터 보내는 코드
               FileInputStream fileInputStream = new FileInputStream("c:\\test\\" + str);

               BufferedOutputStream brs = new BufferedOutputStream(yhd.getOutputStream());
               byte[] bytes = fileInputStream.readAllBytes();
               for(int i=0; i<bytes.length; i++) {
                   brs.write(bytes[i]);
                   System.out.print((char)bytes[i]);
               }
               // 여기까지 보내는 코드

               brs.close();
               serverSocket.close();
               yhd.close();

           } catch (IOException e) {
              throw new RuntimeException(e);
           }
       }
   }

   import java.io.*;
   import java.net.Socket;
   import java.util.Scanner;

   // 클라이언트 클래스
   public class ClientFileTest {

       public static void main(String[] args) {
           try {
               Socket yhd = new Socket("192.168.88.1", 9999);

               // 여기부터 요청하는 코드
               System.out.print("서버에 요청할 메시지를 입력하세요 : ");
               Scanner sc = new Scanner(System.in);

               OutputStream cos = yhd.getOutputStream();
               PrintStream ps = new PrintStream(cos);

               String test2 = sc.nextLine();
               ps.println(test2);
               // 여기까지 요청하는 코드

               // 여기부터 요청받는 코드
               InputStream cis = yhd.getInputStream();
               BufferedInputStream brs = new BufferedInputStream(cis);

               FileOutputStream fileOutputStream = new FileOutputStream("c:\\test2\\" + test2);
               byte[] bytes = brs.readAllBytes();
               for(int i=0; i<bytes.length; i++) {
                   fileOutputStream.write(bytes[i]);
               }
               // 여기까지 요청받는 코드

               System.out.print("요청이 이뤄졌습니다.");

               yhd.close();

           } catch (IOException e) {
               throw new RuntimeException(e);
           }
       }
   }

  • 코드 실행 결과 : C 드라이브 안에 test 폴더에 있는 test01.txt 파일을 클라이언트가 서버로 요청하면 서버에서 해당 파일을 C 드라이브 안에 test2 폴더에 생성시켜준다.

  • 실습 간 알게 된 사실🧐

    • 서버 클래스와, 클라이언트 클래스를 정말 이상없이 작성하고 실행시켰을때, 클라이언트 서버로 파일을 받아와서 해당 폴더에 파일이 생성은 되나, 파일에 작성된 내용이 출력이 안되는 문제가 있었다. 오류가 발생하는 것도 아니라서 정말 해결하는데 어려웠는데, 같이 수업듣는 분께서 해답을 알려주셔서 완성시킬 수 있었다.
    • 안됬던 사유는 딱 1가지였는데, 바로 서버 클래스에서 brs.close()'
      한 줄이었다. 클라이언트 서버로 해당 파일을 BufferedOutputStream 으로 넘겨줬는데, 이 스트림을 닫아주지 않아서 파일이 넘어갈때 내용이 저장되지 않고 넘어간 것이 아닌가 추측된다.
    • 스트림을 열었을때는 반드시 닫아줘야되는 것을 실습을 통해 깨달을 수 있었다.

오늘의 느낀점 👀

  • 오늘 배운 것 중 가장 중요했던 것은 스트림의 이해였던 것 같다. 특히나, 네트워크에 연결하여 서로 데이터를 주고 받는 입/출력에 대해서 실습을 해봤는데, 강사님께서 강조하신게 "소켓 통신이 뭔가요?" 라는 질문에 "채팅 프로그램" 이라는 답변을
    학생들이 많이 한다고 한다.

  • 하지만 이것은 전혀 잘못된 답변이고, 정확히 이해를 못한채로 그냥 사용하는 것이라고 하셨다. 결국에 소켓 프로그램은 네트워크 프로그램을 말하는 것이다. 따라서 소켓 통신은 글자 뿐만 아니라, 파일, 화면, 데이터 베이스 등 다양한 유형을 입/출력 할 수 있도록 해준다.

  • 드디어, 오늘은 네트워크 연결을 프로그래밍으로 간단하게나마 구현해 본 시간이었다. DB 수업때 DB 서버에 연결할때는 리눅스에서 IP 주소를 입력하여 연결했었는데, 방식은 크게 다르지 않았던것 같다. 중요한건, 입/출력 받는 데이터의 형식에 따라 사용하는 스트림의 종류가 다를 수 있다는 점인 것 같다.

  • 이번주는 토요일에 있는 빅데이터 분석기사 실기시험 준비로 프로그래머스는 못풀것 같다. 못한부분은 무사히 시험을 끝내고 다시 시작하려 한다. 수업 시간 중에 틈틈히 풀어보고 있는데, 풀은 문제들은 시험 종료 후 한번에 정리할 예정이다.

profile
Backend Developer

0개의 댓글