본문 바로가기

Node.js

16. Stream

Stream 

 

stream 은 노드에서 스트리밍 데이터를 이용하기 위한 추상 인터페이스이다. 

Types of Stream

 

  • Writable : 데이터를 쓸 수 있는 스트림 ex) fs.createWriteStream()
  • Readable : 데이터를 읽을 수 있는 스트림 ex) fs.createReadStream()
  • Duplex : 읽고 쓸 수 있는 스트림 ex) net.Socket 
  • Transform : 데이터를 읽고 쓸 때 데이터를 수정하거나 변환할 수 있는 스트림 ex) zlib.createDeflate()

Buffering

 

Writable, Readable 스트림 모두 내부 버퍼에 데이터를 저장합니다.

내부 버퍼는 writable.writableBuffer, readable.readableBuffer을 통해 검색되어 집니다.

버퍼에 모일 데이터의 총 크기는 highWaterMark option에 의해 정해집니다. (highWaterMark는 stream 생성자에 의해 전해짐.)

 

stream.push(chunk)를 호출하면 데이터는 Readable stream에서 버퍼링됩니다. 만약 사용자가 stream.read()를 호출하지 않는다면 데이터가 소비되기 전까지 내부 큐에 저장됩니다.

 

내부 읽기 버퍼의 총 크기가 highWaterMark에서 설정한 임계값에 도달하면, 스트림은 현재 버퍼링 된 데이터를 사용할 수 있을 때까지 데이터 읽기를 일시적으로 중지합니다. (즉, 스트림은 읽기 버퍼를 채우는 데 사용되는 내부 Readable._read() 메서드 호출을 중지합니다)

 

writable.write(chunk) 메서드가 반복적으로 호출되면 데이터가 쓰기 가능한 스트림에 버퍼링됩니다. 내부 쓰기 버퍼의 총 크기가 highWaterMark에서 설정 한 임계값 아래라면 writable.write()는 true를 리턴합니다. 내부 버퍼의 크기가 highWaterMark에 도달하거나 초과하면 false가 반환됩니다.

 

스트림 API는, 특히 stream.pipe() 메서드의 핵심 목표는 데이터 버퍼링을 허용가능한 수준으로 제한하여 다른 소스들이 사용해야하는 메모리를 건들지 않는 것입니다.

 

Duplex와 Transform 스트림은 모두 읽기 가능하고 쓰기 가능하기 때문에 각각 읽기 및 쓰기에 사용되는 두 개의 별도 내부 버퍼를 유지합니다. 그리고 각각이 효율적인 데이터 흐름을 유지하면서 서로 독립적으로 작동할 수 있도록 합니다. 예를 들어, net.Socket 인스턴스는 읽기 가능한 쪽이 소켓에서 수신된 데이터의 소비를 허용하고 쓰기 가능한 쪽이 소켓에 데이터 쓰기를 허용하는 이중 스트림입니다.

 

Writable Stream

 

  • HTTP requests, on the client
  • HTTP responses, on the server
  • fs write streams
  • zlib streams
  • crypto streams
  • TCP sockets
  • child process stdin
  • process.stdout, process.stderr

chunk, encoding, callback

 

  • chunk: 쓰기할 데이터(optional), object mode가 아닐 때는 chunk는 무조건 string, Buffer 혹은 Unit8Array이어야만 합니다. object mode일 때는 null 값을 제외한 javascript값이 올수 있습니다.
  • encoding: 인코딩 형식, 만약 chunk가 string이라면 'utf8'이 디폴트 값입니다.
  • callback: 데이터가 모두 쓰여졌을 때의 콜백입니다.
  • Returns: 쓰기 작업이 완료 되지 못했다면 false를 리턴하면서 'drain' 이벤트가 발생되길 기다립니다. 모두 쓰여졌다면 true를 리턴합니다.

Readable Streams

 

  • HTTP responses, on the client
  • HTTP requests, on the server
  • fs read streams
  • zlib streams
  • crypto streams
  • TCP sockets
  • child process stdout and stderr
  • process.stdin

두 가지 타입의 읽기 모드 

 

Readable streams는 2가지의 모드( flowing, paused ) 를 이용하여 효과적으로 작동합니다.

  • flowing 모드에서는 기본 시스템안에서 자동으로 데이터가 읽힙니다. 그리고 EventEmitter를 통해 가능한 빨리 어플리케이션에 데이터를 제공합니다.
  • paused 모드에서는 stream.read() 메서드를 호출하여 스트림에서 데이터 청크를 읽게 만들어야 합니다.

모든 Readable stream은 paused 모드에서 시작합니다. flowing 모드로 변경하기 위해서는 아래 방법을 통해 가능합니다.

 

반대로 flowing에서 puased 모드로 바꾸려면,

 

  • pipe 도착지가 없을때, stream.pause() 메서드를 호출합니다.
  • pipe 도착지가 있을때, pipe 도착지를 모두 지웁니다.(복수개의 도착지가 있을 때는 'stream.unpipe()' 메서드를 호출하면 모두 지워집니다.)

Readable stream 에서 Writable stream 으로 데이터 전달하기 

 

  1. readable.on('data')
  2. readable.on('readable')
  3. readable.pipe()

on('readable')

 

readable 이벤트 : 스트림에서 데이터를 읽을 준비가 되어있으니, 데이터를 언제든지 읽어서 원하는대로 사용하라고 알려주는 이벤트

 

Readable stream의 read 메소드는 Buffer 형식의 데이터를 반환하고, 더이상 읽어올 데이터가 없을 때는 null을 반환하고 stream이 종료된다.

 

on('data')

 

data 이벤트는 데이터를 읽어왔으니, 데이터를 원하는대로 사용하세요_ 를 알려주는 이벤트이다.

data 이벤트 리스너를 등록하는 순간 Readable stream은 flowing 모드로 전환된다. flowing 모드에서 Readable stream은 알아서 data를 읽어오게 된다. 그리고 여전히 Writable stream의 종료를 관리해주어야 한다.

 

pipe()

 

pipe 메소드는 목적지를 알려줄테니 알아서 데이터를 보내줘 를 지시하는 메소드이다. pipe 메소드의 파라미터로 Writable stream 또는 Writable stream을 확장한 Duplex stream이나 Transform stream을 데이터의 목적지로 넘겨줄 수 있다.

pipe 메소드는 시작점이 되는 stream이 데이터를 모두 불러와서 종료되면, 목적지 stream의 end메소드를 호출하면서 종료시켜준다. 개발자가 직접 종료를 관리하지 않아도 목적지 stream이 종료된다.

 

 

 

✔ 출처 및 참고 

 

https://seungtaek-overflow.tistory.com/7

 

[Node.js] Readable Stream을 다루는 방법

Node.js는 데이터를 클라이언트에 전달하거나, 클라이언트로부터 데이터를 받을 때, 또는 파일을 읽고 쓸 때 Readable stream과 Writable stream을 사용하게 된다. 이번에 다룰 Readable stream을 이해하기 위해

seungtaek-overflow.tistory.com

 

 

 

 

'Node.js' 카테고리의 다른 글

18. HTTP transaction  (0) 2022.04.08
17. chunk, buffer , stream  (0) 2022.04.08
15. body-parser  (0) 2022.03.11
14. CORS  (0) 2022.03.11
13. CRUD  (0) 2022.03.07