2020-10-14 TIL

3 minute read

34-c 사용자가 입력한 명령 처리

  • stateful
    • 1) c/s projcet 준비
    • 2) c/s 간에 메시지 송수신 테스트
    • 3) 사용자 입력값 송수신
    • 4) 다중 클라이언트 요청 처리
    • 5) 스레드 적용
  • stateless
    • 6) stateful -> stateless 전환
    • 7) 스레드 재활용 -> 스레드풀
    • 8) 기능을 옮긴다

사용자가 입력한 명령을 서버에 전송하기 - 클라이언트앱

  • 프롬프트를 가져온다.
  • 클라이언트 앱을 변경해서 사용자가 입력한 명령을 보낼 수 있게 만든다.

terminal

  • 백엔드에 서버가 있고 사람들은 terminal을 사용했다.
  • 1980 년대 IBM terminal
  • 터미널에는 모니터, 키보드 네트워크 연결만 있다.
  • 본체 하나에 여러 터미널이 연결되어 있어서 멀티 프로세싱 개념이 있었다.

  • pc가 발달하면서 pc 하나를 여러 사람이 썼다.
  • 개인별 pc가 지급된 다음에는 파일을 외부 pc를 하나 두고 파일을 저장했다.
    • 여러 사람이 중복으로 사용했을 대 파일을 덮어쓰는 문제가 발생함.
    • 이를 해결하기 위해 순서를 정해서 각자 시간차를 두고 사용함.
  • 불편함을 해결하기 위해 pc에 app을 설치하고 그 앱이 파일을 관리하도록 하고 개인별 pc의 앱은 요청을 하도록 했다.

어플리케이션 아키텍처

  • 데스크탑
  • c/s 어플리케이션
  • 어플리케이션 서버
  • 웹 어플리케이션 서버

입출력

  • FileDB
    • 파일 입출력을 위해 만들어 둔 프로그램
    • 파일끼리의 관련이 없는 경우에 사용함
  • c/s
    • 클라이언트(pc)와 서버(DB)로 나눠서 사용
    • 해킹 문제가 생김
    • 프로그램이 업그레이드 될때마다 재설치
  • WAS(Web Application Server)
    • 어플리케이션을 실행하는 서버
    • 데이터베이스 서버
    • pc는 어플리케이션을 실행하는 서버에 접속하도록 한다.
    • 웹이 발달
    • 어플리케이션을 실행하는 서버는 웹 서버
    • 클라이언트는 브라우저 사용
  • 모바일 환경이 발달
    • 화면이 다름
    • 프론트 HTML, Css, java script / 백 java, sql / 모바일 android, ios 로 세분화 됨

반복해서 클라이언트의 요청을 처리한다 - 서버앱

  • 앱 변경
    • 반복해서 클라이언트에게 응답한 후 종료하지 않고 계속 요청을 처리한다.
    • 클라이언트가 quit 명령을 보내면 클라이언트와 연결을 끊는다.

응답 프로토콜 정의

  • 응답을 완료한 다음에는 종료의 의미로 빈줄을 보낸다.

클라이언트 연결

  • 클라이언트와 연결을 끊은 후 다음 클라이언트와 연결한다.

34-e

  • 서버앱의 핸들 클라이언트에서 예외를 던졌을 때 아무도 받지 않으면 아래쪽의 캐치문에서 예외를 받아서 그대로 서버를 종료해버린다.
    • 이 문제를 해결하기 위해서 던져진 예외를 핸들 클라이언트를 호출한 쪽에서 받아서 처리하거나 아래쪽의 핸들 클라이언트 메서드 안에서 자체적으로 처리하게 할 수도 있다.
    • 이것은 선택의 문제.
    • 보통 스레드라면 메서드 안에서 자체적으로 처리해야 한다.
      • 스레드는 실이고 하나의 라인
      • 스레드를 별도로 만드는 것은 별도의 실을 만드는 것
      • 다른 실에서 발생한 예외를 메인 스레드가 받을 방법이 없다.
    • 스레드가 아니라면 호출한 쪽에서 처리해도 괜찮다.
  • stateful 방식으로 하면 한 명이 서버에 접속했을 때 다른 사람이 서버에 접속할 수가 없다.
    • 그래서 멀티 스레드가 필요하다.
  • 서버가 윈도우일때
    • java -Dfile.encoding=UTF-8 -cp bin/main com.eomcs.pms.ServerApp
    • 윈도우즈가 서버일 때 자바 프로그램은 밖에서 들어오는 것을 다 ms949로 인식하고 있다.
    • 클라이언트가 맥일 경우 보내는 파일은 utf-8이다.
  • 같이 통신하려면 같은 네트워크에 있어야 한다.

43-f 동시에 여러 사람의 요청을 처리하고 싶을 때 - 멀티스레딩

  • 클라이언트의 요청을 처리할 clientHandler를 새로 만든다.

  • try (Socket socket = this.socket; BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream())) {

    while (true) {
      String request = in.readLine();
      sendResponse(out, request);
      if (request.equalsIgnoreCase("quit"))
        break;
    }
    

    } catch (Exception e) { System.out.println(“클라이언트와의 통신 오류”); }

    System.out.printf(“클라이언트(%s)와의 연결을 끊었습니다.\n”, address.getHostAddress()); }

  • this.socket을 socket으로 다시 받는 이유는 이렇게 하면 try 블록에서 떠날 때 close()를 자동 호출할 수 있기 때문이다.

  • 인스턴스 멤버를 사용하지 않는 필드는 스태틱으로 하는 것이 원칙이다.
  • ex) private static void sendResponse(PrintWriter out, String message) { out.println(message); out.println(); out.flush(); }
  • 하지만 받은 파라미터 값만 사용할 때도 인스턴스로 만들 때가 있다.
  • ex) private void sendResponse(PrintWriter out, String message) { out.println(message); out.println(); out.flush(); }
  • 왜냐? 지금은 인스턴스를 사용하지 않지만 나중에 인스턴스 멤버를 사용하는 코드가 삽입될 수가 있기 때문에 처음부터 인스턴스 멤버로 만든다.

  • 서버 변경
    • 클라이언트 요청 처리를 클라이언트 핸들러에게 맡긴다.

중첩 클래스

  • 중첩 클래스가 바깥 클래스의 인스턴스 멤버를 쓴다는 것은 바깥 클래스의 특정 인스턴스에 종속된다는 것이다.
    • 마깥 클래스의 특정 인스턴스 멤버를 사용할 일이 없기 때문에 static nested class로 만든다.
    • 인스턴스 멤버인 경우 inner class
  • 3) 중첩 클래스로 만들었을 경우 서버와 연결하는 것은 스레드 밖으로 빼야한다.
    • 왜? 서버와 연결된 다음에 스레드를 실행해야 하기 때문에.
    • 스레드 안으로 넣으면 안된다.
  • 4) 익명 클래스의 코드를 바깥 클래스의 멤버로 만들어 놓고 사용한다.
    • 왜? 코드를 읽기 쉽도록 하기 위해서
    • 코드가 여러 블록에 중첩되면 될수록 들여쓰기를 하면서 코드를 읽기가 불편해진다.
  • 5) 람다 문법 적용
    • 인터페이스인 경우 메서드 명 지우기
    • 메서드 바디만 남기기
    • 화살표
    • 한 줄일 경우 중괄호 없앨 수 있음

34-g pms 코드를 c/s로 분리

  • 1) Json 데이터 포맷을 다룰 Gson 라이브러리를 추가한다.
    • build.gradle 파일에 gson 라이브러리 정보를 추가한다.
    • 터미널을 사용해 폴더에서 gradle eclipse 를 실행한다.
    • 리프레시
  • 2) 기존 애플리케이션에서 관련된 패키지 및 클래스를 가져온다.
    • 도메인 패키지
    • 핸들러 패키지
    • 컨텍스트 패키지
    • 리스너 패키지
    • 앱 클래스에서 옵저버 패턴과 관련된 코드
  • 3) client 의 stop 명령을 처리한다.
    • 서버앱에 stop 변수 추가
    • 클라이언트와 연결할 때 stop의 상태가 true 이면 서버를 멈춘다.
  • 4) 서버에 stop 명령을 보내면 클라이언트를 즉시 종료한다.

  • 5) 서버앱에 옵저버를 추가한다.
    • 서버를 띄울 때 터미널을 사용하면 gson 파일이 없다고 나온다.
    • 외부 라이브러리를 사용하기 때문에.
      • .classpath 가 라이브러리 정보를 가지고 있다.
      • .classpath의 정보를 가지고 이클립스가 command Line을 만들어서 실행한다.
    • 클라이언트의 요청을 처리하는 command 객체를 준비한다.
      • RequestMappingListener 클래스를 만들고 App에서 필요한 코드를 복사해온다.
      • context에 리스트와 커맨드 객체가 다 담겨있다.
    • RequestMappingListener를 등록한다.
  • 6) 클라이언트 명령이 들어오면 커맨드 객체를 찾아 실행한다.

Categories:

Updated: