본문으로 건너뛰기

IO시그널 기초 실습

본 글에서는 iosignal-cli 프로그램을 설치 후 IO시그널의 기초 개념과 사용법을 체험해봅니다.

CLI(Command Line Interface) 프로그램이란 윈도우 명령창이나 리눅스 터미널 창에서 문자 명령어로 실행 가능한 프로그램을 뜻합니다. NodeJS 를 지원하는 맥, 윈도우, 리눅스 모두에 설치 가능합니다.

iosignal-cli 설치 후 명령어 한줄만 입력만 하면 IO서버와 클라이언트 실행할 수 있으므로 비전문가도 설치하여 사용할 수 있습니다. 교육 용도 뿐 아니라 실제 서버 운영 및 테스트에 사용될 수 있는 유용한 프로그램입니다.

iosignal-cli 설치하기

우선 NodeJS 개발환경이 설치되어 있어야 합니다. NodeJS(노드 제이에스)란 자바스크립트(Javascript)언어로 서버 및 데스크탑 프로그램을 만들수 있는 개발 환경입니다.

1. NodeJS 를 먼저 설치해줍니다.

아래의 공식 사이트를 방문하면 운영체제에 따른 설치 파일을 다운로드 할 수 있습니다. 설치할 버전을 선택해야할 경우 LTS(공식안정) 버전을 선택하시는것이 좋습니다. NodeJS 개발 환경은 윈도우(Windows), 맥(Mac), 리눅스(Linux) 운영체제 모두를 지원합니다. 자세한 설치방법은 이미 여러 환경 별로 자세하게 소개된 공개 글을 참고하시는것이 더 좋을것 같습니다.

https://nodejs.org

노드 개발환경을 설치 후 터미널 환경에서 npm 이란 명령을 사용할 수 있습니다.

NPM(Node Package Manager)을 이용하면 개발환경에 필요한 소스 코드나 프로그램을 다운로드해서 설치할 수 있습니다. iosignal-cli도 NPM 명령문을 통해 설치하게됩니다.

2. npm 명령으로 설치

윈도우 환경인 경우 cmd(명령프롬프트) 창을 이용하거나 좀더 많은 기능을 제공하는 파워쉘(PowerShell)을 설치한 뒤 사용할 수 도 있습니다. 주의 할 점은 명령 프롬프트를 실행시 관리자 권한으로 실행해주셔야 합니다.

CLI 프로그램으로 설치하여 사용하기 위해선 전역(global)설치라는 걸 해줘야 하므로 -g 옵션을 반드시 포함시켜야 합니다.

$ npm install -g iosignal-cli

맥과 리눅스 환경의 경우도 관리자 권한으로 설치가 필요하므로 sudo 라는 명령을 통해서 실행해줘야합니다.

$ sudo npm install -g iosignal-cli

(필요시 관리자 암호입력)

3. iosignal-cli 명령어

CLI 프로그램이 잘 설치된 경우 터미널 명령창에서 아래의 명령어를 실행 할 수 있습니다.

  • io-server : IO시그널 서버를 시작 합니다.
  • io-client : 서버에 접속하는 클라이언트 프로그램을 시작 합니다.
  • 단축명령어
    • io-server 대신 ios 을 사용해도 됩니다.
    • io-client 대신 io 을 사용해도 됩니다.

4. 서버 실행하기

별도의 옵션없이 io-server 라고 명령하면 기본 포트번호(port 7777)로 웹소켓 연결이 가능한 서버가 구동됩니다.

$ io-server

// 기본 포트 번호 7777 로 서버가 작동됨

웹소켓 포트번호 지정하기

옵션 -l (Listen ) 과 숫자를 이용하여 웹소켓 연결용 포트 번호를 지정할 수 있습니다.

  • 주의사항. 소문자 l(엘)입니다. 대문자 L옵션은 웹소켓이 아닌 아두이노 접속용 콩소켓 포트 번호를 지정합니다.
$ io-server -l 5555   // 포트 5555번으로 웹소켓 연결을 받을 경우

서버나 클라이언트 프로그램을 종료하려면 .exit 명령을 입력하거나 일반적인 프로그램 종료 명령인 ctrl+c 키를 누르면 됩니다.

옵션 없이 서버를 실행 후 종료하지 말고 다른 새 터미널창을 열고 아래와 같이 클라이언트 실행을 해보세요

5. 클라이언트 실행

io 명령어를 옵션이 없이 실행할 경우, 로컬호스트(동일 컴퓨터)에서 구동되는 서버의 기본포트(7777)로 웹소켓 접속을 시도합니다. 위에서 서버를 옵션 없이 실행 후 종료 하지 않은 상태에서, 새로운 터미널 창을 열어서 옵션 없이 io 명령을 실행하면 위 서버에 연결 됩니다.

$ io

// 옵션없이 실행시 아래와 동일

$ io -c ws://localhost:7777

  • c (connect 접속)옵션 사용

보통 클라이언트가 서버에 접속하려면 -c(connect접속)옵션을 이용하여 프로토콜 이름(ws or wss), 서버의 주소 및 포트 번호를 명시해줘야 합니다. 기본 웹소켓 연결은 ws://url:port 의 형태이고 ws:// 이 프로토콜을 명시하는 부분입니다. 웹소켓 포트가 TLS 로 암호화되는 경우 프로토콜을 wss:// 으로 명시합니다. ws와 wss의 차이는 웹브라우저의 통신 내용이 노출되는 http 연결과 통신 연결이 SSL/TLS로 암호화 되는 https 차이로 이해하시면 됩니다.

// 로컬 서버 접속시

$ io -c ws://localhost:7777

// 외부 서버 접속시 예.

$ io -c ws://test.remocon.kr:7777

// 443 포트로 TLS기반 웹소켓 접속을 받는 서버의 경우 포트번호가 생략될 수 있습니다.

$ io -c wss://server.com/ws

6. 시그널링(메시지 전송) 기본

본 글에서는 서버를 경유한 클라이언트들간의 메시지 소통(메시징)을 포괄적으로 시그널링이라고 표현합니다. IO시그널은 시그널링 규칙(프로토콜)을 기본 제공합니다. MQTT 브로커 같은 채널명으로 구독/발행(Pub/Sub)하는 기능과 더불어 새로운 시그널링 규칙을 추가하였습니다. 즉, 이미 MQTT 를 사용해보신 분들이 익숙한 publish, subscribe 명령을 사용할 수도 있습니다. 하지만 MQTT 에서 제공하는 채널명의 패스(Path)개념 등이 지원되지 않는 등의 큰 차이가 있습니다. 참고로 시그널은 패스(path)라는 개념 대신 타겟(target)과 토픽(topic)으로 구성되는 태그(tag) 개념을 사용합니다. 일단은 태그를 MQTT에서 구독 발행시 사용하는 채널명으로 생각하시면 됩니다.

우선은 MQTT 같은 PubSub 메시징에 이미 익숙한 분들을 위해 구독과 발행 명령에 해당하는 대체 명령어를 소개합니다.

일반적인 PubSub 기반 브로커는 아래와 같은 명령문을 사용합니다.

  • subscribe 채널을 구독하는 명령입니다.
  • publish 채널로 발행하는 명령입니다.

IO시그널 경우 대체 용어를 사용합니다.

  • subscibe 대신 listen , publish 대신 signal 명령어를 사용합니다.
  • listen 은 구독(subscribe)의 기능과 함께 발행된 메시지가 수신된 경우 어떻게 처리할지를 정의하는 명령입니다.
    • 프로그래밍 환경에서는 구독하는 채널 태그와 함께 핸들러 함수를 등록합니다.
    • CLI 환경에서는 구독할 태그(채널명)를 지정해주는 기능을 하며, 메시지 수신 핸들러 함수를 정의할 수 없으므로 수신된 메시지를 단순히 화면에 출력해 줍니다.
  • signal 은 발행(publish)을 대체하는 이름으로 채널을 사용하는 발행 개념보다 좀 더 포괄적인 신호 전달을 의미 합니다.
  • publish와 subscribe 함수도 마찬가지로 사용 가능합니다. 별도 문서로 소개드립니다.
  • 참고로 CLI 환경에서 명령문은 항상 앞에 점(dot) ‘.’ 을 붙여서 입력합니다.

7. CLI 명령문과 개발환경에서 함수 호출문의 차이

프로그램 개발환경에서는 아래와 같은 함수 호출문을 사용하지만

io.listen('channel', handlerFunction )

io.signal('channel','message')

CLI 명령창 환경에서는 아래와 같이 띄어 쓰기로 명령과 인자값(태그, 메시지 등)을 구분합니다.

> .listen channel
> .signal channel message

8. 시그널 전송

CLI 프로그램을 설치 후 아래의 예제로 따라해 보시면, 시그널링의 기본 기능을 체험해보실 수 있습니다. 여기서는 가장 기본이 되는 멀티캐스트와 유니캐스트의 개념을 실습 예제로 소개하고 있습니다.

8-1. signaling 유형

  • 멀티캐스트(multi-cast): 채널을 구독한 구독자 모두에게 메시지를 전송합니다.
  • 유니캐스트(uni-cast): 하나의 특정 수신자에게만 메시지를 전송합니다.

가령 채널 구독자가 다수인 경우 한번의 발행 메시지가 다수의 구독자에게 전달되게 됩니다. 일반적인 PubSub 메시징을 멀티캐스트로 볼 수 있습니다. 채널명만 알면 누구나 송신 및 수신이 가능합니다.

이와 달리 특정한 클라이언트에게만 메시지를 전달하는 경우를 1:1 통신 또는 유니캐스트이라고 표현합니다. IO시그널의 경우 유니캐스트 부분에서 기본 PubSub 메시징 방식과 차별화 된 기능을 제공합니다. 아래 예제는 시그널링을 통해 이 두 방식의 통신이 어떻게 수행되는지 참고하실 수 있습니다. 홈채널이나 토픽(topic)등을 포함하는 고급 태그 사용법은 별도의 문서로 소개 드리겠습니다.

8-2. 준비

화면에 3개의 터미널 창을 열어 준비합니다. 1개는 서버, 나머지 2개는 클라이언트로 사용하게 됩니다.

8-3. 서버 구동

첫번째 화면에서 아래와 같이 입력하여 서버를 구동합니다. 서버는 포트 7777 을 통한 웹소켓 연결을 대기합니다.

$ io-server

// 서버 실행 시 출력되는 정보들은 서버에서 사용되는 포트번호 같은 다양한 옵션 상태를 알려줍니다.

8-4. 클라이언트 A

이번엔 아래와 같이 io 명령을 실행하여 클라이언트 A를 구동하여 로컬 서버에 접속하게 합니다.

$ io

channels: Set(0) {}
Connecting to ws://localhost:7777
ready: cid:?7SbD

접속이 성공할 경우 ready 라는 표시가 뜨고 뒤에 나오는 ?7SbD 가 CID입니다. 여러분 화면에는 다른 값이 뜹니다.

CID(Communication ID) 커뮤니케이션 ID란? 
IoT 장치들이 서로 소통할 때 사용하는 고유값으로 이메일(email) 주소 같은 역활을 합니다.

접속 시도 후 뜨는 ready 는 서버에 접속 뒤 서버로부터 CID를 부여 받은 상태를 의미하며 동시에 통신(시그널링)이 가능한 상태임을 알려줍니다. 만일 ready 표시가 뜨지 않은 경우 서버와의 접속에 문제가 있는 경우입니다. CID 는 1:1 통신에서 사용되는 중요한 정보입니다. email주소를 알아야 메일을 보낼 수 있듯이 CID를 알아야 다이렉트 시그널 전송이 가능합니다.

현재와 같이 로그인 과정이 없이 접속한 경우 서버는 익명 접속 클라이언트용 임시 CID 값을 부여 합니다. 이 값은 해당 접속 중에만 유효하고 매번 접속시 마다 변경됩니다. 반면 로그인 인증을 완료한 디바이스의 경우, 서버에 이미 등록된 고유 CID값이 사용됩니다.

8-5. 클라이언트 A에서 listen 명령으로 구독하기

특정 채널로 발행되는 메시지를 수신하고자 할 경우엔 listen 명령문과 채널명을 입력해주시면됩니다. listen 명령을 사용하면 채널을 구독하고, 메시지가 수신 되면 메시지를 화면에 출력해줍니다.

주의. iosignal-cli 프로그램내에서 명령문을 입력할때는

  • 명령문 앞에 .(점,dot)문자를 붙여줘야합니다.
  • 명령문 외에 인자값이 1개 이상인 경우 공백문자(띄어쓰기,space)로 구분합니다.
  • 참고로 CLI 환경에서는 핸들러 함수를 등록할 수 없으므로 subscribe 과 listen 둘 다 동일하게 구독 및 수신된 메시지를 화면에 출력해주는 역활을 합니다. 개발환경에서 listen 명령과 subscribe 명령은 차이가 있습니다.
// 클라이언트 A.

$ io // 접속
{}
channels: Set(0) {}
Connecting to ws://localhost:7777
ready: cid:?7SbD>

> .listen channel_name // listen 명령으로 채널 구독 및 수신시 화면 출력 요청
listen tag channel_name
channels: Set(1) { 'channel_name' }
<< AUTO_SUBSCRIBE_PROMISE channel_name

8-6. 클라이언트 B 도 접속합니다.

8-7. 채널에 시그널 전송하기(멀티캐스트)

클라이언트 A가 이미 channel_name 이라는 채널명으로 구독을 한 상태입니다. 이 채널에 시그널을 전송(메시지를 발행)하면 구독자인 A가 메시지를 수신할 수 있습니다.

  • .signal channel_name message // (점)시그널 채널명 메시지
  • .publish channel_name message // publish 문을 사용해도 동일한 기능을 합니다.
  • .sig 와 .pub 같은 단축어를 사용할 수 있습니다.
// 클라이언트 B.

$ io //접속
Connecting to ws://localhost:7777
ready: cid:?rr75>

> .signal channel_name some_message // 채널에 시그널을 보냅니다.

// 클라이언트 A.   시그널을 수신한 화면

$ io
{}
channels: Set(0) {}
Connecting to ws://localhost:7777
ready: cid:?7SbD>
> .listen channel_name
listen tag channel_name
channels: Set(1) { 'channel_name' }
<< AUTO_SUBSCRIBE_PROMISE channel_name

> listen: target: channel_name args: [ 'some_message', 'channel_name' ] // 수신된 시그널 표시

클라이언트 A가 채널을 통해 발행한 메시지가 화면에 출력 됩니다. 해당 채널을 구독한 클라이언트가 여러개인 경우, 모든 구독 클라이언트가 동일한 메시지를 받게 됩니다.

  • 수신된 시그널 정보를 보면 메시지와 함께 태그명도 함께 전달 됨을 알 수 있습니다.
  • 프로그래밍 환경에서는 시그널에 포함된 태그 정보도 활용할 수 있습니다.

다음은 1:1 통신을 해보겠습니다.

8-8. A가 B에게 다이렉트 시그널 송신(유니캐스트)

유니캐스트의 경우도 멀티캐스트와 동일한 시그널(signal)명령을 사용합니다. 차이점은 태그(tag) 정보입니다. 태그 정보에 채널명 대신 수신자의 CID와 @ 문자를 입력합니다. @ 문자를 추가하는 이유는 1:1 전송임을 명시적으로 표현하기 위합니다. 메시지를 중계해주는 서버는 태그에 @ 문자가 포함된 경우 유니캐스트로 처리할 수 있어서 손쉽게 멀티캐스트 시그널과 구분할 수 있습니다.

시그널 송신자

  • 수신자의 CID 를 확인합니다. 현재 B의 CID는 ?rr75 입니다.
  • 주의. 임시 CID 의경우 앞에 있는 ? 문자도 CID의 일부입니다. 빼먹지 마세요.
  • cid에 @ 문자를 붙이면 1:1 시그널 용 태그값이 됩니다.
  • [시그널명령] [태그] [메시지] 로 구성됩니다.
  • .signal cid@ message.

  • .signal ?rr75@ direct_message

// 클라이언트 A

> .signal ?rr75@ hello // 다이렉트 시그널 송신

시그널 수신자

  • CLI 프로그램의 경우 1:1 메시지는 별도의 구독 명령어 입력이 없어도 화면에 표시됩니다.
  • 다이렉트 시그널을 수신한 경우 태그값에서 CID 가 제외된 것을 알 수 있습니다.
  • 수신 시그널 태그가 (CID가 생략되어) ‘@’문자로 시작되는 경우 유니캐스트 메시지를 받았음을 알 수 있습니다.
// 클라이언트 B

> rcv @ [ 'hello', '@' ] // 다이렉트 시그널 수신

9. 인증(Authentication)

서버를 구동할 때 인증의 사용 여부와 인증 데이타베이스를 어떻게 연동할지를 결정할 수 있습니다. 인증 관련 옵션의 지정이 없이 구동할 경우, 서버는 인증 기능을 사용하지 않습니다. iosignal-cli은 보통 개인이 간단히 사용하기 용이한 1개의 인증 파일을 이용하는 인증 방식과 Redis 같은 전문 데이타베이스 연동하는 예제를 함께 포함하고 있습니다. 이 부분은 별도 문서로 소개 드리겠습니다.

10. Arduino 연결 포트 설정

시그널 서버는 두 종류의 소켓 접속을 지원합니다. 웹브라우저나 일반 프로그램들은 웹소켓으로 접속할 수 있습니다. 반면 아두이노(Arduino)의 경우 좀더 경량의 콩소켓(CongSocket)으로 접속하게됩니다. 아두이노 접속용을 허용하려면 -L 옵션으로 콩소켓 접속용 포트번호를 지정해주면 됩니다.

  • l(소문자 엘) 옵션으로 웹소켓 포트번호를 지정하고
  • L (대문자 엘) 옵션으로 아두이노 접속 용 포트를 지정해줍니다.
$ io-server -l 7777 -L 8888

// 웹브라우저는 7777 번 포트로 접속하고 아두이노는 8888번 포트로 접속하는 경우

11. 아두이노 라이브러리와 예제 소스

아두이노 라이브러리 매니저에서 IOSignal 을 검색하여 설치하실 수 있습니다. 또는 GitHub 소스 저장소 [ioSignal-arduino](https://github.com/remocons/ioSignal-arduino)  를 참고하시기 바랍니다.