Hayden's Archive

[자바/Java] 스트림(Stream) 본문

Study/Java & Kotlin

[자바/Java] 스트림(Stream)

_hayden 2020. 4. 24. 10:09

- 오늘까지 배우는 내용은 Stand-alone Application( https://en.wikipedia.org/wiki/Standalone_software )

- 자바 개발의 핵심은 분산

- 콘솔로 입력해서 콘솔로 출력보는 것=로컬. 1 Tier(로컬머신)

- 자바 언어의 마지막 챕터는 소켓(Socket). Remote 환경으로 감. 분산 환경.

- 소켓 = 로컬 머신끼리 네트워크로 서비스가 가능한 것.

- 2 Tier : 데이터를 보내는 입장(서버 사이드), 데이터를 받아서 처리하고 다시 돌려주는 입장(클라이언트 사이드) --> 이걸 하게 되면 채팅이 가능. 로컬 머신에서 two tier(서버/클라이언트)이 가능. 

 

- 3 Tier(클라이언트-서버-DB)웹기반. 2008년부터는 4 Tier로 쓰던 걸 Framework로 틀었음.

- 얼마나 분산해서 쓰느냐에 따라 기술에 확 달라짐.

- 데이터가 관을 통해서 날아감. 데이터는 stream을 통해 날아감. 
- 랜선의 끝단이 소켓. 
- ip주소 넣으면 랜선의 끝단에서 stream을 뽑아내게 됨. 외부 stream을 우리가 만들어냄. 데이터가 거기로 날아감. 

- 데이터를 제대로 보낼려면 Object Stream으로 보냄. 객체로.

- 소켓으로부터 관을 터서 만들어주는 것

- 내가 받은 데이터를 영구적으로 보관하려면 DB에 저장하는 것.


- 웹이 쓰리티어
떨어져있으면(=Remote 환경이면) 연결해야 한다->그게 바로 통신.
==> 통신은 여러가지. ftp(파일 연결), http 등 -> 여기서는 소켓

- 통신 = 연결하는 규약(프로토콜). 연결하는 지점이 있으면 다른 걸 쓴다.

- 소켓 통신에서는 가상의 프로토콜... 60000..
- 특정 포트 이내에 있는 가상의 프로토콜

클라이언트-서버 ==> Socket 통신
서버-DB ==> JDBC 통신

- mySQL
3306 쓰도록 되어 있음. 그 포트 쓸 것.

 

- Stream... 시냇물... 데이터 근원지(Generator). 소스에서 싱크로 데이터가 흐르는데 이걸 연결해놓은 게 스트림!

- 파일에 있는 내용을 읽어서 파일에 출력할 수도 있음. 메모리에 있는 내용도 읽을 수 있음

- 스트림 - 데이터가 흘러가는 통로.  스트림을 만들 때 상하수도 공사를 하는 게 아니라 이미 만들어져있음.
이 로컬 머신 안에 키보드 시스템과 콘솔 시스템이 이미 연결되어 있음(아키텍쳐적인 측면에서 다 만들어져 있음)
파일 시스템과 파일 시스템, 메모리와 콘솔 -> 이런 하드웨어적인 매커니즘은 다 만들어져 있음
이미 만들어져 있는 스트림을 우리가 쓰는 것 = 그것을 자원은 연다고 한다.

- 위의 스트림은 로컬 머신 안에서 만들어져 있는 스트림.

- 근데 소켓으로부터 만들어진 스트림.

- 스트림은 크게 두 종류.
내부적으로 만들어져 있는 스트림, 로컬 머신 외부에 연결되어져 있는 스트림(ex:다음 서버 제주도에 있음)

- 데이터가 시작되는 지점이 소스
- 데이터가 도착되는 터미네이터 싱크
- 그 사이를 스트림이 연결

- 하나의 스트림을 통해서 읽고 쓰고 동시에 못함. 입력 스트림은 입력만 하고 출력 스트림은 출력만 함.


<Stream의 기본 구조>
1. FIFO(First in First out) 구조 - 큐 구조 (<-> stack 구조 - 먼저 들어간 게 가장 나중에 나옴.)
a를 제일 먼저 입력하면 a가 제일 먼저 출력된다
2. 단방향(양방향 아님. 입력 스트림은 읽기만 하고 출력 스트림은 쓰기만 함.)

 

캐릭터 -> 8비트가 아니라 16비트 데이터 통과하게 됨(한글, 중국어, 아랍어 등 안 깨짐)
내가 보내는 데이터가 문자 기반이면 캐릭터 계열을 써야 함. 끝나는 게 reader나 writer로 끝나면 캐릭터 계열. 문자 기반의 데이터를 읽어들이고 출력하는 스트림.
read() write() 2바이트씩(한 글자씩) 읽어들임.

바이트 계열 스트림은 8비트를 씀. 영어는 아스키코드 기반이라서 안 깨짐. 근데 다른 언어는 깨짐. 문자 기반의 데이터를 주거니 받거니 하는 게 아님. 이미지 같은 것, 동영상 같은 것들은 바이트 계열로 보냄. 바이너리 데이터 다 바이트 계열 스트림이 담당.
read() write() 1바이트씩 읽어들임.

객체는 오브젝트 계열 스트림이 보냄(따로 다룰 것)

java.io - (io = input output)

서브 클래스가 너무 많을 때 일일이 다 못봄.
그럴 때는 Hierarchy를 본다. 
전부 다 쓰기보다 쓰는 애가 씀.

자바 챕터 중 가장 쉬운 게 스트림.
공부하는 방법을 이해하면 쉬움. 패턴이 똑같음.

 

스트링은 래핑해서 씀. 관을 하나 만들고 오버래핑해서 하나 더 만듦. 
-> 래핑하면 겹쳐지는 부분이 생김. 감춰지는 공간. buffered. 
여기서 한줄로 쌓을 수 있음(엔터키를 만들 수 있음. 여기서 리드라인이라는 메소드가 생성될 수 있음.)
데이터 조작이 가능해짐. 하나하나 읽으면 시간 많이 걸려서 한줄씩.
그래서 스트링은 래핑해서 씀.

리더/라이터로 끝나면 캐릭터 계열.
InputStreamReader / BufferedReader


키보드로 읽어들인 데이터를 콘솔로 출력하는 기능
-> 스트림 작성하는 패턴
1. 스트림 생성 (이미 만들어져 있는 자원을 열어 쓰는 것)
2. 데이터 읽어들인다

3. 콘솔을 출력한다. System.out.println(); ==> 콘솔로 출력할 때는 스트림 만들 필요 없고 그냥 쓰면 된다. 
한줄씩 읽었으면 한줄씩 뿌려야 됨. 한줄씩 읽었는데 하나씩 뿌리면 에러남.

=========================

file을 읽어들일 건데 파일에도 문자 있으니까 스트링 계열 스트림을 쓸 거임. 그래서 리더로 끝남.
그래서 FileReader 클래스! 객체 생성... 
BufferedReader는 다 갖다 쓰면 됨.

이클립스에서 파일 만들 때 안 보이면
new - Other - General - File로 만들기...

============================== 

소스나 싱크를 직접 물고 있는 스트림.
FileReader가 파일(소스)을 물고 있음. ==> 이런 걸 기본 스트림이라고 함. 원서에서는 Node 계열이라고 함.
소스랑 싱크에 직접 연결 안 되고 스트림을 물고 있는 것 ex)BufferedReader ==> 이런 걸 보조 스트림이라고 한다. 원서에서는 Filter 계열이라고 함.

DataInputStream -> 바이트 계열 스트림. 입력 스트림. 
DataInputStream(InputStream in) 생성자 인자값이 스트림. 따라서 Filter 계열!

PrintWriter -> 캐릭터 계열 스트림. 출력 스트림.
Node, Filter 둘 다 쓸 수 있음. 굉장히 뛰어난 것.
PrintWriter(File file)
PrintWriter(OutputStream out)

=========================

java.io - PrintWriter에서 생성자 보면
PrintWriter(Writer out, boolean autoFlush)
--> 자동으로 뿌리기

java.io FileWriter에서 생성자 보면
FileWriter(String fileName, boolean append)
boolean append --> true 하면 이어쓰기

====================
Object Stream
스트림을 통과하는 게 객체!

객체를 보낼 때... 필드에 있는 값이 보내짐.
객체의 값은 필드에 있는 값을 말함.

생성자와 메소드는 스트림 통과 대상이 아님.
필드에 있는 값이 스트림을 통과하는 것!!

뭉쳐있던 필드에 있던 값들이 직렬화되어짐. Serializable
ObjectOutputStream 객체를 뽑아내는 스트림. 직렬화!!

읽어들이는 건 ObjectInputStream로 읽어드림. 역직렬화
 
직렬화 ObjectOutputStream // 데이터가 unpack되는 것... 
역직렬화 ObjectInputStream

중요함!!

// 여기까지는 로컬 머신 안에서...

 

================================


Socket..
분산... Remote 환경
분산되었을 때 연결하는 방법 = 프로토콜 (이때 반드시 포트라는 게 지정되어야 함. 포트는 프로토콜에 따라 다 제각각)
소켓 통신에서의 포트는 1~65535까지의 포트를 선다. 1~1024번가지의 포트는 예약되어 있다. 우리가 쓸 수 있는 포트는 1025~65535 중에 가상의 포트를 쓰면 된다.

서버를 먼저 만들어야 함. 서버가 가동되어야 클라이언트가 달라붙음.
클라이언트만 돌리면 안 됨. 서버가 먼저 돌고 있어야 함. 그리고 클라이언트가 접속.
서버측 어플리케이션을 먼저 구동시켜야 함.

머신의 맨 끝단이 랜. 여기서 소켓을 받아내야 함. 그러면 스트림이 만들어짐.

서버는 여러명의 클라이언트의 접속을 맞아들일 수 있어야 함. 1대 다의 관계.

 

java.net-ServerSocket
A server socket <★★★★★waits for requests to come in over the network.>
서버 소켓은 네트워크로부터 들어오는 요청을 기다린다.
하루종일 기다림!

accept()
기다리는 메소드. Socket을 반환.

소켓을 생성 = 서버측으로 접속. 따라서 접속하고자 하는 서버측 주소를 넣어야 함.
클라이언트가 소켓을 생성하는 순간, 서버측으로 접속하는 순간 ==> accept(). 소켓이 하나 리턴됨. 소켓은 서버가 만들어낸 소켓이 아니라 클라이언트가 만들어낸 소켓.



==============

 

java.net-Socket
This class implements client sockets (also called just "sockets")
소켓은 클라이언트소켓을 의미. 서버측에는 서버소켓이 있다.

A socket is an endpoint for communication between two machines.
두 개 머신을 커뮤니케이션 하는 데 있어서의 끝점이다. (이게 바로 랜선!)

포트는 서버 소켓이 가지고 있고 소켓을 만드는 데 똑같은 포트를 가져야 한다.

모든 요청은 서버가 받는다. reception desk의 역할.
모든 요청은 서버소켓을 거쳐야 한다! 직접적으로 커뮤니케이션을 안 한다. 거치기만 하고 다른 곳으로 돌림.

소켓을 가지고 스트림을 만들어야 함. 이 일을 전담하는 스레드 필요...
소켓이 리턴되자마자 생성되어야 하는 것 => 스레드.
스레드가 소켓을 가져가야 함. 스레드가 스트림을 가지면서 이런 일을 해야 함.
스레드의 run 메소드를 통해서 데이터 주거니 받거니...
프로세스는 다시 while 돌려서 recpetion desk 역할을 함..

여러 사용자의 소켓... 점점 늘어남... ArrayList로 관리.
빠져나가면 나갔다고 얘기해야 함.
List 같은 것 있어야 함......... 추가하거나 제거하거나...

소켓으로부터 스트림 받음. 
소켓 클래스에서

채팅은 브로드캐스팅... 둘이서 채팅할 때 둘 다 모두 창에 떠야 함.
채팅은 자기가 쓴 메세지가 서버 창에 뜨는 게 중요한 게 아니라 자기 창에도 떠야 함.

프로세스에 선언해야 하는 필드 / 스레드에 선언해야 하는 필드 ===> 나눌 수 있어야 한다... 
프로세스적인 기능을 뽑음... 스레드는 run 밖에 없음..