2022-02-07(월) 13주차 1일

Jeongyun Heo·2022년 2월 7일
0

com.eomcs.net.ex03

com.eomcs.net.ex03.Server0140.java

소켓을 연결해서 거기가까지가 네트워킹

파일 입출력은 flush()를 하지 않아도 출력하는 경우
네트워크는 반드시 flush() 해야 되는 경우가 있음
파일로 출력하나 네트워크로 출력하나 flush() 하면 되잖아

Socket socket = new Socket("localhost", 8888);
서버의 대기열에 등록되는 순간 객체가 생성된다.
accept 할 수 있도록 대기열에 들어간 거
대기열이 꽉 차있으면 refused 거절됨

DataOutputStream 데코레이터를 붙인다
DataInputStream 데코레이터를 붙인다
→ 서로 주고 받는 합이 맞음

accept 해야지 클라이언트와 연결되는 게 아님
서버의 대기열에 등록되는 순간 이미 연결이 된 거
연결된 클라이언트와 승인하는 게 accept

try - with - resources

/Users/nana/git/bitcamp-study/java-lang/app

JVM 프로퍼티
-D프로퍼티명=값
중간에 공백 넣으면 안 됨

java -Dfile.encoding=UTF-8 -cp bin/main com.eomcs.net.ex03.Client0140

writeInt()
writeByte()
출력은 블로킹이 없다

readInt()
readByte()
블로킹한다

byte stream을 사용할 때는 바로 출력한다.
character stream은 flush()를 하지 않으면 안 된다

writeInt()
readInt()
순서 맞아야 됨

com.eomcs.net.ex03.Client0150.java

PrintStream
out.println("ABC가각간");
한 줄의 문자열을 출력할 수 있는 메서드가 있다
엔터(0D 0A)를 포함해서 보낸다

Scanner
in.nextLine();
한 줄의 문자열을 읽을 수 있는 메서드가 있다
데코레이터는 아니지만 데코레이터 역할을 한다

byte stream을 사용할 때는 바로 출력한다.
OutputStream / InputStream으로 끝나는 게 byte stream
Writer / Reader로 끝나는 게 character stream

com.eomcs.net.ex03.Server0160.java

BufferedOutputStream 데코레이터 붙임
BufferedInputStream 데코레이터 붙임

바이트 스트림이라 할지라도 버퍼는 조심해야 됨

랜카드 메모리에 안 들어갔다는 거
버퍼 바이트 배열에 보관된 상태임
아직 랜카드 메모리에 안 들어감

버퍼를 사용할 때는 데이터를 보내기 위해 반드시 flush()를 호출해야 한다.

try - with - resources
close() 해서 flush()가 호출돼서
close()를 호출하면 close() 내부에서 flush()를 실행한다.
그래도 서버쪽도 그냥 flush() 명시해주기

그냥 반드시 명시해주기

com.eomcs.net.ex03.Client0210.java

BufferedReader
in.readLine();
한 줄 읽는 메서드가 있다

PrintWriter
out.println(str);
한 줄 출력하는 메서드가 있다

character stream 클래스의 경우
출력 데이터를 내부 버퍼에 보관하고 있다가
버퍼가 꽉차거나 flush()를 호출할 때 출력을 수행한다.

character stream은 BufferedWriter를 안 붙여도 내부에 작은 버퍼가 있으니까 주의하기

BufferedWriter를 붙이지 않아도 이렇게 동작하기 때문에 주의하라!

byte stream이든 character stream이든 무조건 flush() 호출하기

com.eomcs.net.ex04

네트워킹 - 연결 방식

🔹 connection-oriented
연결 지향
TCP 통신
연결 후 데이터 입/출력
예) 전화

🔹 connectionless
UDP 통신
연결 확인 없이 데이터 송신
예) 편지, 삐삐 (대상이 특정되어 있다)
모르스 신호, 무전기 (broadcasting)
ping

ping www.etnews.co.kr

🔹 connection-oriented : stateful, stateless

🔸 stateful
연결 후 여러 번 데이터 송수신
명시적으로 연결을 끊을 때까지 작업

연결 → 전송 → 수신 → 끊기
         반복

예) FTP, Telnet, 채팅

🔸 stateless
연결 후 한 번의 데이터 송수신
자동 연결 끊기

연결 → 전송 → 수신 → 끊기 (반복하지 않음)

예) HTTP, 메신저

com.eomcs.net.ex04.Client0110.java

서버든 클라이언트든 종료할 때까지 계속 데이터를 주고 받는다
보통 클라이언트에서 연결을 끊음

작업 시간에 연결 시간이 포함이 안 됨

게임 서버
화상 통신
유튜브 라이브 채팅
텔렛: 원격 제어 프로그램 (EC2)
상담원과 통화

114 안내
전형적인 stateless 방식

주문은 stateless 방식
쿠폰에 도장을 찍는
네이버에 갈 때 쿠폰을 제시해서 구분
웹 브라우저가 쿠폰을 받았다
고객 번호가 박혀 있는 쿠폰을 받음
쿠키 라고 한다
쿠키에 고객 번호가 적혀 있다

stateful vs stateless

stateful
고객 - 상담원
상담원은 문의 내용을 보관
고객 상태 유지

stateless
고객 - 114
요청/응답 후 즉시 연결을 끊는다

🔹 stateful
✓ 연결되어 있는 동안 클라이언트 정보를 유지
→ 이전 작업 결과를 기억할 수 있다
✓ 클라이언트가 명시적으로 연결을 끊을 때까지 유지
→ 클라이언트의 요청이 없더라도 연결 유지
→ 메모리 낭비
예) 전용 기사, 고급 식당의 전용 웨이터 등
단점 : 소수의 고객에 대응 → 자원 낭비
메모리 많이 차지

🔹 stateless
✓ 요청할 때마다 연결
→ 이전 작업 결과를 기억할 수 없다
→ 매번 연결해야 하기 때문에 데이터 송/수신 시간이 더 걸린다
→ 항상 연결 시간 포함하기 때문
✓ 응답 후 연결 끊기
→ 더 많은 고객 대응
예) 대리 운전 기사, 일반 식당 웨이터 등
단점 : 고객의 상태를 모른다
연결 시간 더 걸림
서버에서 상태를 기억하지 않아서 매번 알려줘야 됨
서버는 더 많은 클라이언트에 응답할 수 있다

단발성 요청에 대한 응답은 stateless
검색, 메일, 채팅은 stateless 방식
게임은 stateful 방식

com.eomcs.net.ex04.Server0120.java

이게 stateful 방식
순차적으로 처리한다
앞에 클라이언트가 연결을 끊을 때까지 다음 클라이언트는 기다린다
먼저 accept 된 클라이언트가 연결을 끊을 때까지

com.eomcs.net.ex04.Server0130.java

break loop;

com.eomcs.net.ex04.Client0210.java

사용자 인증, 인가 작업을 해야 돼서 시간이 많이 걸림

더 많은 클라이언트의 요청을 처리할 수 있다.

스레드를 쓰지 않고도 여러 개의 클라이언트를 처리하는 방법

edx.org

계산기로 해보자

java -Dfile.encoding=UTF-8 -cp bin/main com.eomcs.net.ex04.stateful.CalcClient

영속성을 갖는 작업을 처리할 때는
그런 서비스를 처리할 때는 stateful 방식

27 + 3 - 13 + 5

stateful의

com.eomcs.net.ex04.stateful2.CalcClient.java

작업 결과를 유지할 변수
int result = 0;

값 2개 안 받고 연산자랑 값 하나를 받는다

java -Dfile.encoding=UTF-8 -cp bin/main com.eomcs.net.ex04.stateful2.CalcClient

클라이언트가 중간 계산 결과를 유지할 필요가 없다

stateful의 장점

stateful의 단점
먼저 접속한 클라이언트의 요청 처리가 끝날 때까지

socket.getRemoteSocketAddress();
SocketAddress의 서브 클래스인 InetSocketAddress 객체를 리턴한다
인터넷에 연결됐을 때는 InetSocketAddress

getAddress() → IP 주소 리턴
getPort() → 포트번호 리턴

Socket socket2 = socket;
try 블럭을 나갈 때 socket.close() 자동으로 한다

run()
main() 메서드 호출과 분리하여 별도로 실행할 코드가 있다면 이 메서드에 둔다.

이렇게 하면 stateful 방식이어도

클라이언트가 접속하면 서버가 스레드를 만든다
데이터를 주고 받는 일을 스레드와 작업한다

서버와 스레드

① 접속
클라이언트가 서버에 접속하면
② 생성
스레드 생성
③ start() ← 내부적으로 run() 호출
클라이언트는 스레드에 요청하고 스레드가 클라이언트에 응답

main thread

Thread : 실

main() 메서드의 실행 흐름

JVM이 main()을 호출
main()에서 또 다른 메서드 호출
그 메서드에서 또 다른 메서드를 호출
종료 = JVM 실행 종료

✓ 실행 흐름은 실처럼 시작에서 종료까지 계속 연결되어 있다.

이 실을 부르기를 main thread (주 스레드) 라고 한다.
실행 흐름은 절대 끊기지 않는다. 반드시 연결되어 있다.
어쨌든 맨 마지막에는 main()에 도착한다.
main() 메서드가 끝나는 순간 JVM은 종료하게 되어 있다.

main thread와 child thread

new Thread() ← 새로운 실행 흐름을 만든다

기존의 실행 흐름과 상관 없이 흐른다.

어떤 스레드는 main 메서드보다 더 오래 실행될 수도 있다.
이럴 경우 종료되지 못하고 대기
실행이 끝났다 하더라도 대기
대기하고 있다가 자식 스레드가 종료되면 종료된다.
→ 모든 자식 스레드가 종료되어야만 main thread가 종료된다.

new Thread() → 새 실행 흐름 생성 및 시작

JVM의 모든 스레드는 병행적으로 수행한다.
병행적 : CPU 스케줄링에 따라 CPU 사용권을 받아 작업을 수행한다.
→ 동시에 실행되는 효과를 가진다. (실제로 동시에 실행되는 건 아님)

스레드 간에 실행을 간섭하지 않는다.
얘는 얘대로 자기 갈 길을 간다.

클라이언트가 접속할 때마다 새 스레드를 만들어서 start() 시킨다
실행은 각자 따로따로 한다

전동 킥보드 -> CPU
동시에 진행되는 것처럼 보이지만 실제 CPU는 한 개

코어가 4개면 진짜 동시에 4개 실행하는 거
물리적으로 코어가 많을수록 진짜로 동시에 실행한다
싱글 코어보다 멀티 코어가 성능이 더 좋다

클라이언트 요청이 들어오면 스레드를 만들어서 start()

스레드로 부모 자식 관계가 있다

자식 스레드가 또 자식 스레드가 생길 수 있다

부모 스레드와 동등한 CPU 사용 권한을 갖는다

stateful의 치명적인 단점을 스레드를 통해서 해결할 수 있다
연결된 클라이언트가 연결을 끊기 전까지는
대기하고 있는 다른 클라이언트의 요청을 처리할 수 없다.

java -Dfile.encoding=UTF-8 -cp bin/main com.eomcs.net.ex04.stateless.CalcClient

stateless
데이터를 보내는 순간 접속이 됨

스레드를 쓰지 않아도 클라이언트를 동시에 처리하는 효과

연산 결과를 보관하지 않는다.

com.eomcs.net.ex04.stateless2.CalcServer.java

clientId = 0 (아직 클라이언트 아이디가 없다는 의미)
resultMap에 put
resultMap에 put 하기 전이라 clientId로 get 해도 안 나옴

stateless에서 클라이언트를 구분하는 방법

대기열에 들어간 상태
accept() 하면 한 명 연결됨

c1 c2 c3

① accept() 하면 c1과 통신할 소켓 생성

② 고객ID

③ 연산자

④ 값

    고객 테이블
고객 번호 | 계산 결과
고객번호계산 결과
------------

값을 입력 받고 소켓 생성함

서버는 클라이언트가 누군지 모름
누군지 구분
고객 아이디로 구분

Client ID = 세션 ID

result = obj; // auto-unboxing

신규 고객한테 아이디 발급

브라우저 여러 개가 떠있으면 같은 브라우저로 취급

메일
내 아이디를 같이 준다

그 서버로부터 Client ID(Session ID)를 발급받는다

내가 누군지 Session ID로 구분한다

세션 ID는 로그인 안 해도 웹 브라우저에게 발급한다

매번 서버가 발급
그래서 달라짐

브라우저를 닫으면 가비지가 된다
가비지가 쌓임
네이버 서버
일정 시간이 지나면 가비지들 다 지움
브라우저 안 닫아도 타임 아웃

이게 statelesss에서 클라이언트를 구분하는 방법

인터넷 뱅킹은 10분 제한

보통 쿠키는 웹 브라우저를 닫으면 사라지는데

쿠키를 막는다
쿠키를 주고 받지 않겠다는 거
로그인 안 됨
세션이 관리가 불가능하기 때문에 로그인 자체도 불가능

쿠키
서버에서 브라우저쪽으로 보내는 데이터
응답 헤드에 실어서 보내는 데이터
서버에 다시 요청할 때마다 매번 다시 보냄

클라이언트 ID는 서버에서 최초로 발급
은행은 10분 지나면 무효화 시켜버림

stateless는 스레드 안 써도 문제 없네요? 그렇지 않음!!
스레드를 써야 됨
하나의 요청이 오래 걸리면 기다리는 건 똑같음
멀티-스레딩
스레드는 운영체제거 사용함
스레드 객체
운영체제가 만듦
스레드는 JVM이 손댈 수 없음
운영체제 네트워킹 기능 사용
운영체제 스레드를 대신 사용하는 거
운영체제가 만든 스레드를 가리키는 껍데기
리눅스에서 만든 스레드가 동작하는 방식과
윈도우에서 만든 스레드가 동작하는 방식이 다름

윈도우 : Round-Robin (RR)
모든 프로세스에게 CPU 배정을 균등하게 배분

리눅스 : Priority + Aging
우선순위가 높은 프로세스에게 더 자주 CPU를 배정

최초로 접속하면 세션 ID
로그인 하기 전에 내가 누군지는 세션 ID 발급

stateless + Thread

stateless도 순차적으로 처리함

해결책? 멀티 스레드

현재 스레드만 슬립하는 거

실행 흐름을 분리시키는 이유임

Single Thread와 Multi Thread

­ 1. Single-threading
main thread
① accept
② 클라이언트 요청을 순차적으로 처리
앞선 클라이언트의 작업이 끝날 때까지 뒤의 클라이언트 작업은 지연된다

­2. Multi-threading
① accept
② 각 클라이언트에 대해 별도의 실행 흐름으로 분리한다
새 스레드
클라이언트 당 1개의 스레드가 요청 처리 담당
다른 스레드의 작업 속도에 영향 받지 않는다

node.js가 싱글 스레드 방식

0개의 댓글