2022.08.18/자바정리/리팩토링/HashTable/ArrayList/Client연결/컬렉션API

Jimin·2022년 8월 17일
0

비트캠프

목록 보기
24/60
post-thumbnail
  • board-app 프로젝트 수행
      1. Client/Server 리팩토링
      • Hashtable, ArrayList 활용
      • 클라이언트 연결을 순차적으로 처리
  • 컬렉션 API 사용법(com.eomcs.basic.ex03.*)(계속)

프로그램 실행과 경로

  • C:\Users\bitcamp> a.exe(엔터)
  • a.exe
    • Windows
    1. 현재 경로에서 찾는다.
    2. OS의 PATH 환경 변수에 등록된 경로를 순서대로 찾는다.
    • Unix
      → Unix의 경우 현재 경로를 명시해야한다.
      ./a.exe
      C:\Users\bitcamp\a.exe
      ../a.exe
      C:\Users\a.exe
      ../../a.exe
      C:\a.exe
      ../../dev/a/a.exe
      C:\dev\a\a.exe
  • .: 현재 폴더
  • ..: 상위 폴더

프로그램 실행: Windows

  • a.exe : 컴파일된 기계어 명령 실행 파일
    → 실행
    • > a.exe (exe는 생략 가능)
    • > a
      1. a.com 찾는다 (기계어 파일)
      2. a.exe 찾는다 (기계어 파일)
      3. a.bat 찾는다 (OS가 이해하는 스크립트로 작성된 명령어가 들어있는 파일로, 컴파일이 불필요하다.)

프로그램 실행: Unix

  • a.exe : 컴파일된 기계어 명령 실행 파일
    → 실행
    • $ a + 엔터 (PATH 환경 변수에 등록된 경로를 따라가며 찾는다.)
    • $ ./a + 엔터 (현재 폴더에 있는 파일을 실행하고 싶으면 경로를 명시해야한다!)
  • Unix에서는 실행 파일에 대해 사용자가 실행권한을 가지고 있어야만 실행할 수 있다.
  • $ ls -al
  • 실행 권한을 2진수로 표현
    644 ⇒ rw-r--r-- a : 실행파일에 대해 사용자에게 실행권한을 부여하지 않았기 때문에 실행할 수 없다.
    • rw- : user 권한
    • r-- : group 권한
    • r-- : other 권한
    • a : 실행 파일명
  • 실행 권한 부여
    $ chmod 744 a
    744: 111(7) 100(4) 100(4)
    • 111: rwx (x는 실행권한)
    • 100: r--
    • 100: r--

⇒ 이제 실행 가능


Shell Script와 기타 Script 실행

1. Shell Script

  • OS 내부의 인터프리터를 사용해서 스크립트 실행
    a.bat + 엔터
    a + 엔터

2. 기타 스크립트

node hello.js

  • node: JavaScript를 실행시켜줄 인터프리터, 이게 진짜 실행시키는 파일
    • 기계어가 아닌 이상, 인터프리터를 앞에 두어야 한다.
  • hello.js: JavaScript 파일, 이거는 그냥 옵션, 부가 정보

Shell Script와 기타 Script 실행: Unix

1. Shell Script

a.sh 파일
⇒ 명령문을 작성할 때 사용하는 스크립트에 zsh, csh, bash, bsh, tsh, sh, ... 문법을 사용할 수 있다.

  • Shell Script 실행 방법:
    $zsh a.sh
    a.sh 파일: 스크립트 파일
    zsh: 스크립트 인터프리터 (스크립트 파일에 사용된 문법 언어에 따라 인터프리터가 달라진다.
    zsh로 실행할 경우, a.sh 스크립트 파일은 zsh 문법 언어로 쓰여진 스크립트 파일인 것이다.)

2. shell script 자동 실행

a.sh 파일: #!/bin/zsh 이 파일을 실행시킬 shell script 인터프리터를 설정한다.
$ cgmod 744 a.sh : a.sh 스크립트 파일에 대해 실행권한을 부여
$ ./a.sh → 쉘 스크립트 파일 실행
이 때, 쉘 스크립트 파일을 실행하는 것이 아니라, zsh가 실행되어 이 파일이 a를 실행시키는 것이다.


Client/Server 리팩토링

목록관리ListSetMap
데이터 저장 및 조회시 사용하는 인덱스값: 0부터 순차적으로 증가하는 정수 값
(양수)
key: hash 알고리즘으로 계산한 정수값hash 알고리즘으로 계산한 정수값
입력 순서 유지OXX
객체 중복 저장OXKey가 중복되지 않는다.
특징입력 순서 유지중복 제거빠른 조회 → key를 이용
- ArrayList
- LinkedList
- Vector
HashSet- HashMap: key, value, null 허용
- HashTable:key, value, null 불가!

board-app project

app-server

1단계 - Servlet 객체의 목록을 HashSet으로 관리한다.

  • com.bitcamp.board.ServerApp 클래스 변경
  • 각각의 인스턴스 객체들 대신 HashSet안에 넣어준다. <키, 값> → <String, Servlet>
	Hashtable<String, Servlet> servletMap = new Hashtable<>();
      servletMap.put("board", new BoardServlet("board"));
      servletMap.put("reading", new BoardServlet("reading"));
      servletMap.put("visit", new BoardServlet("visit"));
      servletMap.put("notice", new BoardServlet("notice"));
      servletMap.put("daily", new BoardServlet("daily"));
      servletMap.put("member", new MemberServlet("member"));
  • switch문 대신 HashTable의 키 값을 리턴하는 것으로 코드를 간결하게 바꾼다.

이전 코드

switch(dataName) {
	case "board":  boardServlet.service(in, out); break;
	case "reading": readingServlet.service(in, out); break;
	case "visit": visitServlet.service(in, out); break;
	case "notice": noticeServlet.service(in, out); break;
	case "daily": dailyServlet.service(in, out); break;
	case "member":memberServlet.service(in, out);break;
	default:out.writeUTF("fail");
            }

이후 코드

Servlet servlet = servletMap.get(dataName); // dataName(key)를 가지고 BoardServlet을 데려옴

2단계 - 여러 클라이언트의 연결을 순차적으로 허용한다.

  • com.bitcamp.board.ServerApp 클래스 변경
    • 하나의 클라이언트가 연결을 끊어도 서버가 유지되어 다른 클라이언트가 연결될 수 있도록 while문을 추가한다.
    • servlet hashMap객체는 while문 밖에 꺼내준다.
    • 클라이언트가 달라질 때마다 그에 맞는 DataInpuStream의 in과 DataOutputStream의 Out 객체가 만들어져서 서버에 전달한다.
  • ServerApp class
package com.bitcamp.board;


public class ServerApp {

  public static void main(String[] args) {
    System.out.println("[게시글 데이터 관리 서버]");

    try (
        ServerSocket serverSocket = new ServerSocket(8888);)
    {
      System.out.println("서버 소켓 준비 완료!");

      // 클라이언트 요청을 처리할 객체 준비
      Hashtable<String, Servlet> servletMap = new Hashtable<>();
      servletMap.put("board", new BoardServlet("board"));
      servletMap.put("reading", new BoardServlet("reading"));
      servletMap.put("visit", new BoardServlet("visit"));
      servletMap.put("notice", new BoardServlet("notice"));
      servletMap.put("daily", new BoardServlet("daily"));
      servletMap.put("member", new MemberServlet("member"));

      while(true) {
        try(
            Socket socket = serverSocket.accept(); 

            DataInputStream in = new DataInputStream( socket.getInputStream()); 

            DataOutputStream out = new DataOutputStream(socket.getOutputStream());
            )//try()
        {
          System.out.println(" 클라이언트와 연결 되었음!");

          while(true) {
            String dataName = in.readUTF(); 
            // 명령 읽기

            if(dataName.equals("exit")) { 
              break;
            }

            Servlet servlet = servletMap.get(dataName); // dataName(key)를 가지고 BoardServlet을 데려옴
            if(servlet != null) {
              // 클라이언트가 달라질 때마다 그에 맞는 in, out을 서버에 전달한다.
              servlet.service(in, out);
            } else {
              out.writeUTF("fail");
            }
          }
          System.out.println("클라이언트와 연결을 끊었음!");
        }// 안쪽 try
      }// 서버 while
    }catch (Exception e) {
      e.printStackTrace();
    }// 바깥쪽 try-catch()

    System.out.println("서버 종료!");
  }//main()
}

app-client

1단계 - ArrayList를 사용하여 Handler 객체를 관리한다.

  • com.bitcamp.board.ClientApp 클래스 변경
    • Handler배열이 대신 ArrayList로 XxxHandler 인스턴스들을 담아준다.

이전 코드

Handler[] handlers = new Handler[] { // 파일명을 목적에 맞게 각각 전달
	new BoardHandler("board", in, out), // 게시판
	new BoardHandler("reading", in, out), // 독서록
	new BoardHandler("visit", in, out), // 방명록
	new BoardHandler("notice", in, out), // 공지사항
	new BoardHandler("daily", in, out), // 일기장
	new MemberHandler("member", in, out) // 회원
};

이후 코드

// 핸들러를 담을 컬렉션을 준비한다.
      ArrayList<Handler> handlers = new ArrayList<>();
      handlers.add(new BoardHandler("board", in, out));
      handlers.add(new BoardHandler("reading", in, out));
      handlers.add(new BoardHandler("visit", in, out));
      handlers.add(new BoardHandler("notice", in, out));
      handlers.add(new BoardHandler("daily", in, out));
      handlers.add(new MemberHandler("member", in, out));

해당 핸들러 실행 코드 → get() 메소드 이용

handlers.get(mainMenuNo-1).execute();
  • ClientApp class
package com.bitcamp.board;

public class ClientApp {

  //breadcrumb 메뉴를 저장할 스택을 준비
  public static Stack<String> breadcrumbMenu = new Stack<>();

  public static void main(String[] args) {
    System.out.println("[게시글 관리 클라이언트]");

    // 네트워크 준비
    //=> 정상적으로 연결되었으면, Socket 객체를 리턴한다.
    try (Socket socket = new Socket("127.0.0.1", 8888 ); 
        DataOutputStream out = new DataOutputStream(socket.getOutputStream());
        DataInputStream in = new DataInputStream(socket.getInputStream());){// 같은 컴퓨터 내에 서버와 클라이언트가 존재하므로 정확한 IP address 대신, 127.0.0.1(local host)이 가능하다. (접속할 IP address, port num)

      System.out.println("연결되었음!");

      welcome();


      // 핸들러를 담을 컬렉션을 준비한다.
      ArrayList<Handler> handlers = new ArrayList<>();
      handlers.add(new BoardHandler("board", in, out));
      handlers.add(new BoardHandler("reading", in, out));
      handlers.add(new BoardHandler("visit", in, out));
      handlers.add(new BoardHandler("notice", in, out));
      handlers.add(new BoardHandler("daily", in, out));
      handlers.add(new MemberHandler("member", in, out));

      // "메인" 메뉴의 이름을 스택에 등록한다.
      breadcrumbMenu.push("메인");

      // 메뉴명을 저장할 배열을 준비한다.
      String[] menus = {"게시판", "독서록", "방명록", "공지사항", "일기장", "회원"};

      loop: 
        while (true) {

          // 메인 메뉴 출력
          printTitle();

          printMenus(menus);

          System.out.println();

          try {
            int mainMenuNo = Prompt.inputInt(String.format(
                "메뉴를 선택하세요[1..%d](0: 종료) ", handlers.size()));

            if (mainMenuNo < 0 || mainMenuNo > menus.length) {
              System.out.println("메뉴 번호가 옳지 않습니다!");
              continue; // while 문의 조건 검사로 보낸다.

            } else if (mainMenuNo == 0) {
              out.writeUTF("exit"); // client가 서버와의 연결에서  나가겠다고 하는 순간. // out은 서버로 보내는 것이다.
              break loop;
            }

            // 메뉴에 진입할 때 breadcrumb 메뉴바에 그 메뉴를 등록한다.
            breadcrumbMenu.push(menus[mainMenuNo - 1]);

            // 메뉴 번호로 Handler 레퍼런스에 들어있는 객체를 찾아 실행한다.
            handlers.get(mainMenuNo-1).execute();

            breadcrumbMenu.pop();

          } catch (Exception ex) {
            System.out.println("입력 값이 옳지 않습니다.");
          }


        } // while

      Prompt.close();

      System.out.println("연결을 끊었음!");
    } catch (Exception e) {
      e.printStackTrace();
    }//try-catch()

    System.out.println("종료!\n");
  }//main()
  
  ...
  
profile
https://github.com/Dingadung

0개의 댓글