이 블로그는 Web 환경을 이용한 원격 제어 기술에 필요한 지식을 공유 하기 위한 블로그 입니다.
실제 개발과 프로그램 예를 위하여 Raspberry Pi와 Raspberry Pi Pico, ATmega128 보드, Arduino Mega 보드(ATmega2560), WiFi 모듈을 사용 합니다.

node-js-startup

Node.js startup
Raspberry Pi 에서 node.js 사용을 위한 준비


  • Node.js 개요
    • JavaScript 기반으로 구성된 서버 사이드 서비스를 JavaScript로 구현할 수 있게 하는 런타임 환경(Runtime Environment: 컴퓨터가 실행되는 동안 프로세스나 프로그램을 위한 소프트웨어 서비스를 제공하는 가상 머신 환경) 이다.
    • Node.js는 Server 측에서 JavaScript를 실행 할수 있게 한다.
    • Node Package Manager(npm)를 이용하여 다양한 node.js 기반의 모듈을 설치 할 수 있고 이를 이용하여 용이하게 Server Side program을 개발 할 수 있다.
    • Event driven programming 과 Callback function
      • 기존의 프로그램 언어(C, C++ 등)는 코드가 순차적으로 실행되면서 함수를 호출(Procedural programming model) 하는 방식으로 프로그램이 실행 된다.

        Node.js는 Event driven 방식(특정 이벤트가 발생되면 미리 이벤트에 맵핑된 함수가 실행된다.)으로 프로그램이 실행 되기 때문에 Node.js 환경의 프로그램을 이해 하기 위하여는 Event driven programming 과 Callback function에 대한 이해가 필요 하다.

        Node.js는 Event-driven, Non-blocking I/O model을 지원 하기 때문에 프로그램 실행 속도가 빠르고 효과 적이다.

      • JavaScript에서 일반 Function의 실행
        • JavaScript 코드는 기본적으로는 동기식(Synchronous)으로 실행된다. 프로그램 코드는 한 라인씩 순차적으로 실행된다.
        • 동기식(Synchronous) JavaScript 프로그램의 실행 예
        • 아래 코드는 문자열을 함수에 매개변수로 전달하여 출력하는 예로 함수가 호출되는 순서에 때라 함수의 실행 결과가 출력된다.

          위 JavaScript 코드의 실행 결과(Output)는 함수가 순차적으로 실행되어 아래와 같이 출력된다.

          주: 아래 "Raspberry Pi에 Node.js 설치하기"와 "원격 컴퓨터에서 PuTTY(SSH 프로토콜 이용)를 사용한 개발 환경"를 참고하여 Node.js를 설치하고 위 프로그램을 복사하여 test.js로 저장하고 실험한다.

      • JavaScript CallBack Function
        • JavaScript에서는 함수(함수의 포인터)를 함수의 인수로 전달할 수도 있다. 다른 함수에 인수로 전달되어 실행되는 함수를 CallBack Function라고 한다.
        • CallBack Function 예
        • 아래 코드에서는 greet() 함수를 호출하며 문자열과 함수(callMe() 함수의 포인터)를 매개 변수로 전달하여 greet() 함수내에서 callMe() 함수가 실행된다. 이 경우 callMe() 함수를 CallBack 함수라고 한다.

          위 JavaScript 코드의 실행 결과(Output)는 greet() 함수가 실행되고 callMe() 함수가 실행되어 아래와 같이 출력된다.

        • CallBack Function의 특징
          • CallBack 함수를 사용하면 먼저 호출된 함수의 실행 결과를 기다린 후 CallBack 함수를 실행할 수 있다.
          • 속도가 느린 입출력 또는 통신 장치를 제어하는 프로그램에서 CallBack 함수를 사용하면 속도가 느린 입출력 또는 통신 프로그램의 실행 결과를 CallBack 함수에서 바로 사용할 수 있게 된다.
          • Node.js 와 같이 비동기식(Asynchronously) 프로그램 실행을 지원하는 경우(Event-driven, Non-blocking I/O model을 지원하는 경우) CallBack 함수를 사용하면 실행 속도가 빠르고 효과적인 프로그램 실행이 가능하다.
          • 주: Callback function이 호출된 함수(속도가 느린 입출력 또는 통신 장치를 제어하는 프로그램)의 실행 결과를 기다리는 동안 다른 실행 가능한 Module이 실행되기 때문에 전체적으로 실행 속도가 빠르고 효과적인 프로그램 실행이 가능하다.

      • JavaScript callback function 예: setTimeout() 함수
        • JavaScript callback function은 비동기 함수(Asynchronous function) 이다.
        • JavaScript callback function는 주어진 작업이 완료 될 때 호출 된다.
        • setTimeout() 함수를 사용하는 예

          위 JavaScript 코드의 실행 결과(Output)는 setTimeout() 함수가 종료되기 전에 mesgOut() 함수가 실행되어 'Hello world' 가 출력되고 약 2초 후에 'Hi, Kim' 이 아래와 같이 출력된다.

      • JavaScript callback function 예: File I/O Programming
        • File I/O Programming 예

        • node-js 폴더를 만들고 cd 명령으로 node-js 폴더로 이동 한다.
        • 아래와 같은 내용의 Text File을 만들어 input_file.txt에 저장 한다.
        • 아래와 같은 callback-test.js File을 만들어 저장 한다.
        • 다음 명령으로 callback-test.js File를 실행 한다.
        • node callback-test.js

        • 실행 결과는 아래와 같다.
        • 윗 예에서 주어진 작업(File Read 동작: 컴퓨터의 실행 속도에 비교 하여 매우 느리게 진행 됨)이 진행 되는 동안
        • Callback function ( function (err, data) { - - - } )은 특정한 Even (이 경우 File Read 동작이 종료 되면 발생 하는 Event)를 기다리고 있는 상태가 된다.
        • Callback function이 Event를 기다리는 동안 다른 실행 가능한 Module (이 예에서는 Console에 메세지를 출력 하는 명령) 다른 Module이 실행( 결과로 "Program Ended" 메세지가 먼저 출력 된다.) 된다.
        • File Read 동작이 종료 되고 Event 가 발생 하면 Callback function이 실행 (Read 된 File의 내용이 Console에 출력) 된다.
        • 이와 같이 Node는 Event에 의하여 실행되는 Callback function을 이용 하여 속도가 느린 I/O 장치의 동작이 종료 되는 것을 기다리지 않고 비 동기적(Asynchronous)으로 I/O 동작을 처리 하여 프로그램의 실행 속도와 효율을 높일 수 있다.

  • Raspberry Pi에 Node.js 설치하기
    • 이 페이지에서는 원격 컴퓨터(Windows OS가 설치된 PC)에서 PuTTY(SSH 프로토콜 이용)를 사용하여 Raspberry Pi에 연결하고, PuTTY 터미널 창을 Raspberry Pi의 콘솔로 사용한다.

      원격 컴퓨터에서 PuTTY 이용을 위한 참고자료: "처음 Raspberry Pi를 시작 하기 -> 원격 접속(SSH, VNC) 설정 하기"

    • Raspberry Pi의 System package를 최신 버전으로 Update 한다.
      • PuTTY 터미널에서 다음 명령으로 System package list를 Update 한다.
      • sudo apt-get update

      • 다음 명령으로 설치된 모든 Package를 최신 버전으로 Upgrade 한다.
      • sudo apt-get dist-upgrade

    • Node.js 설치하기
      • node.js 홈페이지에서 최신 버전을 확인 한다.
      • 다음 명령으로 Package repository의 node.js 정보를 최신 버전으로 Update 한다.
      • curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -

        주: 위에서 16은 node.js 홈 페이지에서 확인한 최신 버전 번호이다. 이 버전 번호는 새 버전이 나올 때마다 계속 변동되기 때문에 최신 버전을 설치하기 위하여는 설치 시 확인이 필요하다.

      • 다음 명령으로 Node.js를 설치 한다.
      • sudo apt-get install nodejs

      • 다음 명령으로 node가 바르게 설치 되었는지 확인 한다. 정상으로 동작하면 node의 버전 번호(예: v16.13.2)가 출력 된다.
      • node -v

      • 다음 명령으로 npm(Node Packaged Manager)이 바르게 동작 하는지 확인 한다. 정상으로 동작하면 npm의 버전 번호(예: 8.1.2)가 출력 된다.
      • npm -v

      • 다음 명령을 실행하여 package.json파일(설치된 Package의 정보(버전 등)을 관리 하는 파일)을 초기화 한다.
      • npm init -y

        주: Raspberry Pi에 OS를 설치하고 처음 node.js를 설치하는 경우에만 초기화가 필요하다. Upgrade만 하는 경우에는 초기화를 하면 기존 package.json에 저장된 정보가 삭제되기 때문에 주의를 요함.

      • 다음 명령으로 package.json파일의 내용을 확인 한다.
      • cat package.json

    • Node.js Upgrade 하기
      • 위 방법으로 Node.js를 설치한 경우에는 이미 최신 버전을 설치 하였기 때문에 Upgrade가 필요 없다. Node.js를 설치 후 최신 버전으로 Upgrade가 필요한 경우 아래와 같이 Upgrade를 실행한다.

      • 다음 명령으로 Node 버전을 확인 한다.
      • node -v

      • 다음 명령으로 Package repository 정보를 최신 버전으로 Update 한다.
      • sudo apt update

      • Major Version으로 Update 하고자 하는 경우에는 다음 명령으로 Package repository 정보를 원하는 버전으로 Update 한다. 아래 예에서 16 가 설치 하려는 버전 번호 이다.
      • curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -

      • 다음 명령으로 Node.js를 설치 한다.
      • sudo apt-get install nodejs

      • 다음 명령으로 node가 바르게 설치 되었는지 확인 한다. 정상으로 동작하면 node의 버전 번호(예: v16.13.2)가 출력 된다.
      • node -v

      • 이전 Node 버전에서 설치된 Package들(GPIO, i2c-bus 등)이 새 Node 버전과 맞지 않아 발생하는 문제를 해결하기 위하여 다음 명령으로 현재 설치된 Package를 다시 rebuild 한다.
      • npm rebuild


  • Node.js 테스트 하기
    • 설치가 완료되었으면 PuTTY를 실행하고 Raspberry Pi에 로그인하여 다음 명령을 실행 한여 본다.
      • 주: 아래 "원격 컴퓨터에서 PuTTY(SSH 프로토콜 이용)를 사용한 개발 환경"을 참고하여 Raspberry Pi에 로그인 한다.

      • PuTTY를 실행하고 Raspberry Pi에 로그인 한다.
      • node_js 폴더를 만들고 cd 명령으로 node_js 폴더로 이동 한다.
      • 정상적으로 설치 되었으면 v16.20.1 과 같이 현재 설치된 버전이 표시 된다.
      • 현재 설치된 npm 버전이 8.19.4과 같이 표시 된다.
      • Node.js 버전 확인 예

    • PuTTY 명령창(REPL Terminal)에서 JavaScript 코드를 입력하여 실행 하기.
      • node 명령을 입력하면 node 가 실행되고 node 명령을 실행 할 준비(Node Prompt 상태 >)가 된다.
      • >   var a = 'Node';      // 변수 a에 Node 문자열이 저장 된다. 다음 줄에 표시 되는 undifined 메세지는 무시 한다. > 문자는 node 명령을 기다리는 Prompt 문자임.
      • >   a                          // `Node` 문자열이 출력 된다.
      • >   var b = 'test';       // 변수 b에 test 문자열이 저장 된다. 다음 줄에 표시 되는 undifined 메세지는 무시 한다.
      • >   b                        // `test` 문자열이 출력 된다.
      • >   console.log(a + ' ' + b);   //enter 'Node test' 문자열이 출력 된다.
      • Ctrl C를 두번 누르면 Node 실행이 중단 되고 Dos Command Prompt 상태가 된다.
      • PuTTY 명령창(REPL Terminal)에서 JavaScript 코드 실행 예

    • JavaScript 파일을 만들고 해당 파일을 실행 하기.
      • 주: File 작성과 실행은 아래 "원격 컴퓨터에서 PuTTY(SSH 프로토콜 이용)를 사용한 개발 환경"을 참고바람.

      • Text Editor를 사용 하여 js-test.js File을 아래와 같이 만들고 저장(예: node_js 폴더에 저장) 한다.
      • PuTTY 명령창에서 "node js-test.js" 명령을 실행 하면 아래와 같이 결과가 출력 된다.
      • node 환경에서 js-test.js를 실행한 예

        주: JavaScript를 실행하기 위하여는 JavaScript engine이 필요하다. 대부분의 Web browser는 JavaScript engine을 포함하고 있기 때문에 HTML 문서 내에 <script> Tag를 이용하여 JavaScript code를 작성하고 Browser에서 실행할 수 있다. 또한 Node.js 도 JavaScript engine를 포함하고 있기 때문에 Node.js 환경에서 JavaScript를 실행할 수 있다.


  • 원격 컴퓨터에서 PuTTY(SSH 프로토콜 이용)를 사용한 개발 환경
    • Raspberry Pi를 원격제어에 이용하는 경우 Raspberry Pi용 모니터와 키보오드를 사용할 수 없기 때문에 PuTTY를 사용한 원격(인터넷으로 연결된 Windows PC에 설치된 PuTTY 프로그램을 이용) 개발 환경을 이용하는 것이 효과적 이다.

      이 예에서는 Windows PC에 설치된 PuTTY 프로그램을 가상 단말기로 이용하고, 프로그램 코드는 Notepad++ 편집기를 사용하여 작성하고, 작성된 프로그램 코드를 WinSCP(FTP 프로그램)을 사용하여 Raspberry Pi 전송한다. 전송된 프로그램은 PuTTY를 이용하여 실행 한다.

      아래에서는 Windows PC에 설치된 PuTTY 프로그램과 Notepad++(프로그램 편집용 텍스트 편집기), WinSCP(FTT 프로그램)를 이용한 개발 환경에 대하여 설명 한다.

    • PuTTY
    • 네트워크 상의 다른 컴퓨터에 로그인하여 원격으로 명령을 실행할 수 있는 가상단말기 프로그램으로 SSH(Secure SHell) 프로토콜 이용하여 보안성이 좋고 다양한 설정이 가능한 무료 오픈소스 프로그램 이다.

      PuTTY를 가상 단말기로 사용하기 위한 Raspberry Pi 설정과 원격접속 방법은 Raspberry Pi 사용을 위한 준비 페이지의 원격 접속(SSH, VNC) 설정 하기ssh 원격접속하기를 참고 하기 바람.

    • Notepad++ 편집기
    • Notepad++는 텍스트 파일을 작성하기 위한 무료 오픈소스 프로그램으로 다양한 옵션과 강력한 편집 기능을 갖고 있기 때문에 다양한 언어의 프로그래밍에 적합하다.

      Notepad++는 Notepad++ Download 페이지에서 다운로드 할 수 있다.

    • WinSCP
    • WinSCP는 Windows용 그래픽 유저 인터페이스를 지원하는 SFTP(SSH File Transfer Protocol) 및 FTP 클라이언트 프로그램으로 오픈소스 프리웨어 이다. 이 프로그램을 사용하여 로컬 컴퓨터와 원격 컴퓨터 간에 안전하게 파일을 복사할 수 있다.

      주: PuTTY에서 생성된 SSH 보안키는 WinSCP와 공유되기 때문에 PuTTY를 먼저 설치한 다음 WinSCP를 설치하면 WinSCP에 별도의 보안키 설정 없이 사용할 수 있다.

      참고자료: WinSCP를 이용한 원격 파일 관리

      참고자료: WinSCP Download 페이지


  • 원격 컴퓨터에서 PuTTY를 사용한 개발 환경을 이용한 프로그램밍 예
    • 아래 예는 "Node test"를 출력하는 프로그램을 Windows PC에서 작성하고, Raspberry Pi로 프로그램 전송하여 실행 하는 예 이다.

    • Notepad++ 편집기를 사용하여 Node.js 프로그램 작성하기
      • Windows PC에서 Notepad++ 편집기를 열고 아래와 같이 프로그램을 작성하여 저장(File name: js-test.js) 한다.
      • Notepad++ 편집기 실행 창 예

    • WinSCP를 이용하여 Raspberry Pi로 프로그램 전송하기
      • WinSCP를 실행하고 Raspberry Pi에 연결 한다.
      • PC에 js-test.js File이 있는 폴더와 Raspberry Pi에 js-test.js File을 저장할 폴더를 설정 한다.
      • js-test.js File을 Raspberry Pi의 해당 폴더로 복사 한다.
      • 주: WinSCP 실행 창에서 마우스 우측 버튼을 사용하여 편집 기능을 선택한 다음 내부(or 외부 편집기)를 이용하여 File을 직접 편집할 수도 있다.

        WinSCP 실행 창 예

    • PuTTY를 이용한 프로그램 실행
      • PuTTY를 실행하고 Raspberry Pi에 로그인 한다.
      • js-test.js File이 있는 폴더로 이동 한다.
      • 아래 명령으로 Node.js에서 js-test.js를 실행 한다.
      • node js-test.js

        PuTTY 실행 창에서 js-test.js 프로그램을 실행한 예


  • Node.js를 이용한 Web server
    • Node.js는 Built-in HTTP Module을 포함하고 있다.

      HTTP 모듈을 이용하여 HTTP 서버를 생성할 수 있고, 생성된 서버는 서버 포트를 이용하여 Client의 요구(Require)를 수신하고 Client에 응답(Response)을 전송할 수 있다.

    • HTTP Module을 이용한 Web Server 예
      • HTTP Module을 이용한 Web Server 예
        • 아래 예는 HTTP server를 생성하고, Client의 요구에 응답하여 'Hello World! 메세지를 전송하는 예 이다.

        • HTTP Module을 이용한 Web Server 실험
          • 위 Code를 복사하여 hello-http.js 파일로 저장(예: node_js\hello-http.js)한다.
          • 주: "원격 컴퓨터에서 PuTTY를 사용한 개발 환경을 이용한 프로그램밍 예"를 참고하여 Notepad++ 편집기, WinSCP를 이용하여 파일의 복사, 편집, 전송 등을 할 수 있다.

          • PuTTY 실행 창에서 "node hello-http.js" 명령을 실행 한다.
          • Web browser를 열고 http://Raspberry Pi의 IP 주소:2880/ 으로 접속 하면 Browser에 "Hello World!" 메세지가 출력 된다.
          • 주: 공유기의 포트포워드 설정에서 Raspberry Pi의 설정을 외부포트: 2880 , 내부포트: 2880 으로 설정하여야 한다. 포트 번호는 본인의 편의에 따라 다른 번호를 사용할 수 있다.


      • HTTP Module을 이용한 Web Server에서 Query String 읽기
        • 아래 예는 HTTP server를 생성하고, Client에서 전송된 url(Query String)를 읽고 확인하는 코드 예 이다. Client에서 전송된 url 종점(Endpoint)을 읽어 다시 Client에 전송하고, PuTTY 실행 창(Console)에 출력한다.

        • Web Server에서 Query String 읽기 실험
          • 위 Code를 복사하여 http-url.js 파일로 저장(예: node_js\http-url.js)한다.
          • PuTTY 실행 창에서 "node http-url.js" 명령을 실행 한다.
          • Web browser를 열고 http://Raspberry Pi의 IP 주소:2880/url-test 으로 접속 하면 Browser에 "/url-test" 가 출력 된다.
          • PuTTY 실행 창(Console)에 'req.url: /url-test' 가 출력되었는지 확인한다.

      • HTTP Module을 이용한 Web Server에서 Query String을 Split 하기
        • 아래 예는 HTTP server를 생성하고, Client에서 전송된 Query String을 Split 하여 확인하고, Client에서 전송하는 예 이다.

        • Web Server에서 Query String 읽기 실험
          • 위 Code를 복사하여 http-querystring.js 파일로 저장(예: node_js\http-querystring.js)한다.
          • PuTTY 실행 창에서 "node http-querystring.js" 명령을 실행 한다.
          • Web browser를 열고 http://Raspberry Pi의 IP 주소:2880/?year=2024&month=May 으로 접속 하면 Browser에 "2024 May" 가 출력 된다.
          • PuTTY 실행 창에서 Query string이 아래와 같이 출력되었는지 확인한다.
          • Query string: 2024 May


      • Node.js 파일 시스템 모듈을 사용한 파일 작업
        • Node.js File system module을 사용하면 컴퓨터의 파일 시스템의 파일 작업(Read, Create, Update, Delete, Rename)을 할 수 있다.
        • 아래 예는 Client의 요구에 응답하여 서버에 저장된 파일을 읽어 Client에 전송하는 예 이다.
        • Node.js 파일 시스템 모듈을 사용한 파일 작업 실험
          • 위 Code를 복사하여 file-read.js 파일로 저장(예: node_js\file-read.js)한다.
          • 아래 Code를 복사하여 file-read.js 파일이 있는 폴더에 file-read.html 로 저장한다.
          • PuTTY 실행 창에서 file-read.js 파일이 있는 폴더(예: node_js)로 이동한다.
          • PuTTY 실행 창에서 "node file-read.js" 명령을 실행 한다.
          • Web browser를 열고 http://Raspberry Pi의 IP 주소:2880/ 으로 접속 하면 Browser에 "file-read.html" 이 출력 된다.
        • 참고자료: File Create, Update, Delete, Rename은 Node.js File System Module 을 참고할 것.

      • Node.js URL Module
        • URL Module을 사용하면 용이하게 웹 주소를 의미있는 부분으로 분리할 수 있다.
        • 아래 예는 웹 주소를 의미 있는 부분으로 나누어 PuTTY 실행 창(Console)에 출력하는 예 이다.
        • Node.js URL Module 실험
          • 위 Code를 복사하여 url-module.js 파일로 저장(예: node_js\url-module.js)한다.
          • PuTTY 실행 창에서 "node url-module.js" 명령을 실행 한다.
          • PuTTY 실행 창에 웹 주소의 Parsing 결과가 아래와 같이 출력되었는지 확인한다.
          • host: localhost:2880

            pathname: /index.html

            search: ?year=2024&month=May

            month: May


      • Node.js를 이용한 File(Web) Server
        • 아래 예는 url 종점(Endpoint)이 'server-red.html' 인 경우 "server-red.html" 파일을 Client에 전송하고, 종점(Endpoint)이 '/server-green.html' 인 경우 "server-green.html" 파일을 Client에 전송하는 예 이다.
        • Node.js File(Web) Server 실험
          • 위 Code를 복사하여 file-server.js 파일로 저장(예: node_js\file-server.js)한다.
          • 아래 Code를 복사하여 file-server.js 파일이 있는 폴더에 server-red.html 로 저장한다.

            아래 Code를 복사하여 file-server.js 파일이 있는 폴더에 server-green.html 로 저장한다.

          • PuTTY 실행 창에서 file-server.js 파일이 있는 폴더(예: node_js)로 이동한다.
          • PuTTY 실행 창에서 "node file-server.js" 명령를 실행 한다.
          • Web browser를 열고 http://Raspberry Pi의 IP 주소:2880/server-red.html 으로 접속 하면 Browser에 "Red page"가 출력된다.
          • Web browser를 열고 http://Raspberry Pi의 IP 주소:2880/server-green.html 으로 접속 하면 Browser에 "Green page"가 출력된다.
          • File read error 가 발생하면 "404 Not Found" 메세지를 Browser에 출력한다.

        주: 위 예와 같이 Node.js 기능만을 사용하여 웹 애플리케이션을 개발하는 것이 가능하다. 그러나 HTTP 요청 및 응답과 같이 낮은 수준 기능을 애플리케이션 작성자가 처리되어야 한다. 그러므로, Express을 사용하여 HTTP 요청 및 응답과 같은 낮은 수준의 일반적인 작업을 Express 가 처리하도록 하면 개발자는 자신이 개발하고자 하는 애플리케이션에 보다 더 집중할 수 있다.

        참고자료: Node.js - Express, Web 서버 개발 시 대부분의 개발자는 "Node.js - Express"를 이용한다.