기본 콘텐츠로 건너뛰기

WEB-RTC 개발 - 1 (WEB-RTC with Nodejs)

WEB-RTC 개발 - 1 (WEB-RTC with Nodejs)

이번시간에 구성해 볼 기능은 첫번째 단계인 사용자가 접속하여 웹 클라이언트 페이지를 받는 단순한 HTTP 서버와,

서로의 신호를 주고받을 수 있는 시그널링 역할을 하는 웹소캣 서버를 만들어 볼 예정이다.

개발 언어로는 Nodejs를 활용할 예정이다.

구현할 기능의 단계는 크게 아래 3가지로 구분되어 진다.

1. http 서버를 구현하여 사용자가 접속하면 화상채팅을 할 수 있는 페이지를 전달하여 준다.

2. 서로가 같은 네트워크에 붙어있음을 확인할 수 있는 시그널링 역할을 하는 웹소캣 서버를 만든다.

3. 서로의 시그널링을 주고받을 수 있도록 웹 페이지에서 웹소캣 서버로 접속을 하는 기능을 만든다.

첫 번째 단계를 위해서 http 모듈을 설치한다.

npm install http

모듈이 설치되고 난 이후에 일반 요청에 대해서 간단한 페이지를 보여주도록 작업한다.

작성할 파일 명칭은 index.js로 하였다.

const http = require('http'); const fs = require('fs'); const port = 3000; //포트 const pathName = './html/index.html'; const server = http.createServer(function(request, response) { //일반 HTTP 요청 처리 fs.readFile(pathName, function (err, data) { if (err) { response.writeHead(404, { 'Content-Type': 'text/html' }); } else { response.writeHead(200, { 'Content-Type': 'text/html' }); response.write(data.toString()); } response.end(); }); }); server.listen(port, function() { console.log((new Date()) + ' Server is listening on port 3000'); });

전혀 어렵지 않는 코드이다. 3000번으로 접속요청이 들어온 경우 html폴더의 index.html 파일을 사용자에게 전달 하도록 하였다.

index.html 파일의 내용은 일단 간단하게 hello world라는 텍스트가 보여지게 하였다.

webrtc Hello world

접속을 하면 정상적으로 Hello world화면이 보여진다.

여기까지가 사용자에게 웹 페이지를 전달하는 기능이다.

해당 기능까지가 웹페이지를 사용자에게 전달하는 내용이다.

다음단계로 사용자가 서로 신호를 주고받을 수 있도록 웹소켓 서버를 작성한다.

웹소켓 모듈을 설치 한다.

npm install websocket

* 웹 소켓 관련 글 주소

https://ko.wikipedia.org/wiki/%EC%9B%B9%EC%86%8C%EC%BC%93

서버코드인 index.js를 1차 수정 한다.

//맨 위의 코드 내용 생략 ----- const WebSocketServer = require('websocket').server; const wsServer = new WebSocketServer({ httpServer: server, //기존에 만든 http서버를 활용 autoAcceptConnections: false //true인경우 서버가 허용하지 않는 기타 요청도 가능해짐 });

위 4줄의 코드 내용이 어렵지는 않다. 내용 그대로 웹 소켓 서버를 기존 구현된 http 서버를 활용해서 구동시키는 내용이다.

다음으로 사용자의 요청에 대해서 신호를 지속적으로 유지하도록 하는 기능을 추가하여보자.

const rooms = new Map(); //커넥션을 담을 객체 wsServer.on('request', function(request) { //응답을 받는다. const user = request.resourceURL.query.user; //사용자 ID var connection = request.accept(); //들어온 커넥션 객체 rooms.set(user,{con:connection}); //커넥션 추가 connection.on('message', function(message) { //서로의 메시징이 도달하면 for(let target of rooms.entries()) { //전달 if (message.type === 'utf8') { console.log('Received : ' + message.utf8Data); target[1].con.sendUTF(message.utf8Data); } else if (message.type === 'binary') { console.log('Received Binary'); target[1].con.sendBytes(message.binaryData); } } }); connection.on('close', function(reasonCode, description) { //커넥션이 끊기면 rooms.delete(user); //삭제 }); });

사용자의 개별 커넥션을 담기 위해서 Map 객체를 사용 하였다. Map 객체에 들어온 요청에 대해서 고유의 키 값을 활용하여 커넥션을 담아 두었다.

"사용자 ID"라는 부분은 고유의 키 값처럼 사용할 내용이며, 사용자가 요청할 때(index.html) 전달하도록 만들 예정이다.

각각의 브라우저가 해당 키 값을 통해서 Map객체에 저장되도록 하기 위해서 이다.

중간에 connection 객체의 on함수에 message로 되어있는 부분이 서로의 메시징이 주고받을 때 하는 행동을 기록한 내용 이다.

* 참고사항 : 무조건 2명이서만 사용하는 기능으로 구현되어 있다. 나중에 map 부분의 기능을 수정하면 채팅방과 같은 기능도 가능 하다.

1차로 완성된 일반 웹 + 시그널링 서버(index.js)이다.

const http = require('http'); const fs = require('fs'); const port = 3000; //포트 const pathName = './html/index.html'; const server = http.createServer(function(request, response) { //일반 HTTP 요청 처리 fs.readFile(pathName, function (err, data) { if (err) { response.writeHead(404, { 'Content-Type': 'text/html' }); } else { response.writeHead(200, { 'Content-Type': 'text/html' }); response.write(data.toString()); } response.end(); }); }); server.listen(port, function() { console.log((new Date()) + ' Server is listening on port 3000'); }); //signal server area ------------------------------------------------------------------------------- const WebSocketServer = require('websocket').server; const wsServer = new WebSocketServer({ httpServer: server, //기존에 만든 http서버를 활용 autoAcceptConnections: false //true인경우 서버가 허용하지 않는 기타 요청도 가능해짐 }); const rooms = new Map(); //커넥션을 담을 객체 wsServer.on('request', function(request) { //응답을 받는다. const user = request.resourceURL.query.user; //사용자 ID var connection = request.accept(); //들어온 커넥션 객체 rooms.set(user,{con:connection}); //커넥션 추가 connection.on('message', function(message) { //서로의 메시징이 도달하면 for(let target of rooms.entries()) { //전달 if (message.type === 'utf8') { console.log('Received : ' + message.utf8Data); target[1].con.sendUTF(message.utf8Data); } else if (message.type === 'binary') { console.log('Received Binary'); target[1].con.sendBytes(message.binaryData); } } }); connection.on('close', function(reasonCode, description) { //커넥션이 끊기면 rooms.delete(user); //삭제 }); });

클라이언트(index.html) 페이지에서는 웹 소켓에 대한 연결, 닫힘, 메시징 전달 기능을 1차로 구현해 보도록 하겠다.

그리고 앞서 만든다고 하였던 고유 id값을 전달 해 주는 기능도 작성해 보겠다.

1차로 작성한 웹소캣 접속 코드이다.

var url = 'ws://127.0.0.1:3000?user=고유아이디필요!!'; var socket = new WebSocket(url); socket.onopen =function () { console.log('connection ok'); }; socket.onclose =function () { console.log('connection fail'); }; socket.onmessage = function (response) { var msg = response.data; console.log(msg); };

웹소캣 객체는 웹표준에 의해서 사용되는 객체이므로 어떤 브라우저든지 간에 동일하게 적용이 된다.

코드 자체가 매우 직관적이라 설명을 생략 한다.

해당 코드에 id를 만들어주는 함수와, 테스트용으로 메시지를 보낼 기능을 붙여보았다.

1차로 완성된 클라이언트(index.html)의 모습이다.

Title var url = 'ws://127.0.0.1:3000?user='+makeid(10); var socket = new WebSocket(url); socket.onopen =function () { //접속 console.log('connection ok'); }; socket.onclose =function () { //종료 console.log('connection fail'); }; socket.onmessage = function (response) { //전달 var msg = response.data; console.log(msg); }; $('#clicker').click(function(){ //웹소켓 서버로 메시징 전달 var value = $('#chat').val(); socket.send(value); }); function makeid(length) { //랜덤아이디 만들기 함수 var result = ''; var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var charactersLength = characters.length; for ( var i = 0; i < length; i++ ) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; }

이제 서버를 구동하여 보자. 브라우저 2개를 켠 뒤에 접속하여보자.

서로 전달받은 메시지가 콘솔창에 뜨는 모습 서버에 도착한 메시지 로그

위 내용처럼 이상없이 동작 하였다면 1차구현 목표에 도달 한 것이다.

오늘 작업 한 개념을 간단히 정리하여보자.

위 사진과 같이 각각의 클라이언트가 동일한 웹 주소로 접속하여 웹소켓 서버를 통해서 시그널링(메시지)을 주고받았다.

서로의 메시지가 정확하게 전달 되었으므로 브라우저간의 1차준비는 완료 된 것이다.

다음시간에는 web-rtc를 적용하는 부분에 대해서 알아보도록 하겠다.

web_rtc_.7z 0.00MB

from http://lts0606.tistory.com/223 by ccl(A) rewrite - 2020-03-06 04:54:05

댓글

이 블로그의 인기 게시물

카카오 오픈빌더와 외부 API 연동(feat.Nodejs)

카카오 오픈빌더와 외부 API 연동(feat.Nodejs) 이전에 플러스 친구와 외부 API 연동에 관한 글을 작성한 적 있습니다. 하지만 지난 2년동안 플러스 친구에 많은 변화가 생겼는데요. 카카오 플러스 친구의 명칭이 카카오 채널로 바뀌고, 챗봇 세팅 방식이 기존 [카카오 플러스 친구 - 외부 API 연동] 구조에서 오픈빌더가 추가되어 [카카오 채널(구 플러스 친구) - 카카오 i 오픈빌더 - 외부 API 연동] 구조로 바뀌었습니다. 이번 글에서는 오픈빌더의 챗봇 시나리오 관리 기능을 간단히 소개하고 외부 API를 연동하는 예제를 다뤄보겠습니다. (연동파트는 5번 항목부터 보시면 됩니다.) 1. 블록 블록은 오픈빌더에서 질의/응답을 관리하는 최소 단위로, 사용자의 발화와 챗봇의 대답을 입력할 수 있습니다. 예를들어 인사라는 블록을 만들고 인사에 해당하는 사용자 발화 패턴들을 입력해두면, 실제 채널 톡방에서 그에 해당하는 발화가 들어왔을때 입력해둔 응답이 나오는 형식입니다. 예전에는 패턴과 발화 키워드가 1:1 매칭, 즉 입력해둔 패턴과 사용자 발화의 string이 정확히 일치할때만 블록이 실행됐었는데, 발화 패턴을 20개 이상 등록하면 머신러닝 기능을 이용할 수 있도록 기능이 생겼습니다. 아마 유사도 분석 개념이 기본으로 들어가있을 것이기 때문에 블록의 주제와 벗어나는 너무 뜬금없는 발화패턴들을 많이 넣지 않도록 하는걸 권장하겠습니다. 2. 시나리오 시나리오는 '블록'들을 묶어서 관리할 수 있는 단위로, 일종의 폴더 구조라고 생각하면 쉽습니다. 오픈빌더에서 좌측 상단에 파란 버튼을 클릭하여 시나리오를 생성할 수 있습니다. 하나의 시나리오에서 모든 블록을 관리하면 챗봇 도메인이 커질수록 관리가 어려워지니 아래 같은식으로 시나리오를 사용하여 블록을 구조화하면 운영 측면에서 수월해집니다. 3. 컨텍스트 컨텍스트는 맥락이라는 뜻 입니다. 오픈빌더에 존재하는 컨텍스트는 자연어 분석을 통해서 맥...

AWS instance로 Nodejs 구현하기

AWS instance로 Nodejs 구현하기 서버와 데이터베이스 관리 차원에서 효율적으로 관리하기 위해선 로컬보다는 서버를 호스팅해서 하는 것이 좋다. 우리는 Nodejs를 구동하기 위해 AWS에서 인스턴스를 할당받을 계획이다. 인스턴스의 pem키를 발급받아 nodejs와 npm까지는 설치를 완료한 상태이다. $ sudo npm install -g express 다음의 명령어를 입력하면 글로벌 옵션으로 어느 path에서든 express를 사용할 수 있게 설치한다. 다음과 같이 실행이 된다면 성공이다. 이후 Express generator를 설치한다. $ sudo npm install -g express-generator@4 버전은 4.x이며 이 역시 글로벌 옵션으로 설치해 준다. 이제 Node monitoring을 위해 nodemon을 설치해 준다. $ sudo npm install -g nodemon 모든 설치가 끝났다. 이제 nodejs를 실행시킬 프로젝트용 directory를 만든다. 이렇게 만들어 주고 express를 실행시키면 된다. $ express -e 다음과 같은 결과가 나오면 된다. 이제 node package를 설치하는 명령어를 입력하자. $ sudo npm install 이제 vi를 통해 포트번호를 정의해보자. app.set의 마지막에 한줄을 추가하면 된다. app.set('port', process.env.PORT || 9000); 이로써 우리는 9000번 포트를 사용하게 되었다. 또한 마지막줄에 서버를 생성하기 위한 코드를 작성하자. module.exports = app; var server = app.listen(app.get('port'), function() { console.log('Express server listening on port ' + server.address().port); }); 이...

20.03.24 ShareBook TIL

20.03.24 ShareBook TIL Project/TIL 20.03.24 ShareBook TIL 중간 배포를 위해 EC2, RDS를 다시 설정하였다. EC2에 git에서 clone을 하고 서버를 작동시켜보니 ts로 돌려서 그런지 작동하지 않고 대기 상태로 있다가 timeout같은 시간 초과 에러가 났다. 그리고 갑자기 EC2 자체가 느려져서 nodejs를 삭제하고 다시 nvm으로 높은 버전의 node를 설치하였다. 그리고 나서 혹시 js로 돌리면 될까 해서 tsc로 js로 변환한뒤 돌려보니 RDS와 연결이 되지 않는 에러가 생겼다. workbench로 RDS를 연결했을 때는 정상적으로 작동해서 EC2에서 잘 못 설정한게 있다고 생각했다. 그래서 local에서 한번 config.json을 수정하고 연결하여도 똑같은 에러가 발생했다. 그럼 보안 설정에서 문제인가 싶어서 EC2, RDS 보안 그룹에서 설정을 막 만져보다 RDS에서 Custom TCP에 처음 RDS에서 설정한 포트를 넣어주었더니 연결되었다. config.json내용을 EC2에도 똑같이 적용시켜보려고 json파일을 vim으로 작성해서 넣어 주었지만 여전히 같은 에러를 반복하였다. 그럼 json 파일을 못 읽어내는게 아닌가 싶어서 그냥 module에 index.js에서 sequelize를 생성하는 부분에 직접 넣어 주었더니 마침내 연결이 되었다. 해결하고 난 뒤 생각의 흐름을 적어보니 매우 짧지만 정작 오늘 아침 10시 반부터 시작해서 저녁 10시 반까지 12시간을 고민하고나서야 해결되었다. from http://three-five.tistory.com/46 by ccl(A) rewrite - 2020-03-25 00:54:05