스트림, 표준입출력, 소켓

스트림(Stream), 표준입출력(Standard I/O), 소켓(Socket)에 대해 이해하고, TCP 통신을 이용해서 CLI 채팅 서비스를 만들어봅니다.
스트림, 표준입출력, TCP, 소켓, 채팅


스트림

OS는 기억장치, 디스플레이, 키보드 등의 주변 장치 및 네트워크와 프로세스 간의 소통을 담당하고 있습니다. 이 때 OS는 주변 장치나 네트워크를 모두 파일로 추상화한 API를 프로세스에 제공합니다.

스트림스트림

이렇게 프로세스와 장치 사이에 데이터를 주고 받을 수 있도록 운영체제가 제공하는 인터페이스를 스트림(Stream) 또는 파일 포인터(File Pointer)라고 일컫습니다. 스트림은 입력 스트림(Input Stream)이나 출력 스트림(Output Stream), 또는 양방향 스트림(Duplex Stream)이 될 수 있습니다.

프로세스와 스트림프로세스와 스트림

프로세스는 키보드나 마우스, 트랙패드, 마이크, 파일 등의 입력 스트림을 통해 데이터를 입력을 받을 수 있고, 모니터나 스피커, 프린터, 파일 등의 출력 스트림을 통해 데이터를 출력 할 수 있습니다.

주요한 스트림

표준 입출력 스트림

프로세스가 생성되면 기본적으로 3개의 스트림이 부착됩니다. 이는 입력(STDIN), 출력(STDOUT), 오류(STDERR)에 관련된 정보를 주고 받기 위한 스트림들입니다. CLI 프로그램에서 STDIN은 키보드 입력 스트림에 연결 되어 있으며, 셸로 실행한 CLI 프로그램의 경우에는 STDOUT, STDERR는 모니터를 통해 출력 될 수 있습니다.

파일 또는 주변 장치 스트림

프로세스는 실행 중에 기억장치의 파일이나, 주변 장치에 입출력 스트림을 생성 할 수 있습니다.
이를 통해서 파일을 읽고, 쓰고, 생성하고 또 주변 장치에 데이터를 읽고 쓸 수 있습니다.

네트워크 장치 (소켓)

프로세스는 실행 중에 다른 프로세스와 네트워크 연결(TCP 또는 UDP)을 맺을 수 있습니다. 이 때 데이터 입출력의 매개가 되는 스트림을 생성하는 데 이를 소켓 (Socket)이라고 부릅니다. 통신은 두 프로세스 사이에 이루어지기 때문에 통신이 이루어지는 각각의 채널마다 소켓이 생성됩니다. 소켓 스트림은 양방향(Duplex Stream)일 수도 또는 단순히 쓰기 전용(Output Stream), 읽기 전용(Input Stream) 일 수 있습니다.

소켓 스트림소켓 스트림

네트워크 소켓(Network Socket)은 컴퓨터 네트워크를 경유하는 프로세스 간 통신의 종착점이다. 오늘날 컴퓨터 간 통신의 대부분은 인터넷 프로토콜을 기반으로 하고 있으므로, 대부분의 네트워크 소켓은 인터넷 소켓이다. 네트워크 통신을 위한 프로그램들은 소켓을 생성하고, 이 소켓을 통해서 서로 데이터를 교환한다… 인터넷 소켓은 다음과 같은 요소들로 구성되어 있다. 인터넷 프로토콜 (TCP, UDP, raw IP), 로컬 IP 주소 및 포트, 원격 IP 주소 및 포트. 인터넷 소켓은 크게 UDP, TCP 프로토콜을 사용하는 두 개의 타입으로 분류할 수 있다… (위키백과)

프로세스와 소켓

이제는 웹 브라우저 위에서 작동하는 단순한 스크립트가 아니라, 단독 프로세스로 실행될 프로그램을 작성하기 때문에, OS가 프로세스에 제공하는 정보나 기능들에 대해서 먼저 살펴 보도록 하겠습니다. Node.js의 Process API에 대해서 알아봅니다.

process 객체의 주요 속성 및 메소드

속성타입내용
process.pidNumber프로세스 아이디(운영체제가 할당해주는 번호)
process.archString프로세스가 실행되는 CPU의 아키텍쳐
process.envObject환경 변수를 담고 있는 객체
process.argvArray프로그램 실행시 전달된 매개 변수들의 배열
process.exitFunction프로세스 종료하기
process.abortFunction프로세스 비정상 종료하기
process.cpuUsageFunction프로세스의 CPU 사용량 반환
process.memoryUsageFunction 프로세스의 메모리 사용량 반환
process.stdinStream프로세스의 표준입력 스트림 객체
process.stdoutStream프로세스의 표준출력 스트림 객체
process.stderrStream프로세스의 표준오류 스트림 객체
process.onFunction<String, Function>프로세스에 이벤트(exit, SIGINT, 등) 핸들러 부착하기

프로세스를 실행 중에 강제로 종료시키려면 Crtl+C 를 누르세요. 프로세스의 표준 입력 스트림에 Crtl+C가 입력되면 OS는 프로세스에 SIGINT라는 신호(Signal)를 보냅니다. 모든 프로세스는 기본적으로 SIGINT 신호를 받으면 프로세스를 종료합니다.
Node.js의 Process API

TCP 채팅 서버

TCP 프로토콜, Node.js의 net 모듈을 이용해서 서버-클라이언트 구조의 CLI 채팅 서비스를 만들어 보겠습니다. 상시 작동하는 서버 프로그램, 최종 사용자들이 이용 할 클라이언트 프로그램 두개가 필요합니다.

const net = require('net');

let sockets = [];
function broadcast(message) {
  sockets.forEach(socket => socket.write(message));
}

let server = net.createServer(socket => {
  sockets.push(socket);
  let ip = socket.address().address;
  broadcast(`${ip}님이 입장하셨습니다.`);

  socket.on('data', data => {
    let packet = data.toString().split('|');
    let name = packet[0] || '아무개';
    let message = packet[1] && packet[1].trim() || '';
    if (message != '') {
      broadcast(`${name}> ${message}`);
    }
  });

  socket.on('close', () => {
    let index = sockets.indexOf(socket);
    sockets.splice(index, 1);
    broadcast(`${ip}님이 퇴장하셨습니다.`);
  });

  socket.on('error', e => {
    console.log(e);
  });
});

const port = process.env.PORT || 5000;
server.listen(port, () => {
  console.log(`Server started at port ${port}`);
});

TCP 채팅 클라이언트

const net = require('net');

// prompt name
console.log('이름을 입력하세요!');
process.stdin.once('data', data => {
  let name = data.toString().replace('\n', '');

  // connect to server
  let socket = net.connect(5000, '192.168.1.150', () => {
    socket.on('data', data => {
      console.log(data.toString());
    });

    process.stdin.on('data', data => {
      let message = data.toString().replace('\n', '');
      let packet = `${name}|${message}`;
      socket.write(packet);
    });
  });
});
이 강의를 포함한 커리큘럼
저자

김동욱

개발 경력 약 10년, 전문 분야는 웹 및 각종 응용 소프트웨어 플랫폼입니다. Codeflow를 운영하고 있습니다.

2018년 04월 12일 업데이트

지원되지 않는 웹 브라우저거나 예기치 않은 오류가 발생했습니다.