본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


WEB-RTC

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

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2019. 10. 15.

 

 

이번시간에 구성해 볼 기능은 첫번째 단계인 사용자가 접속하여 웹 클라이언트 페이지를 받는 단순한 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라는 텍스트가 보여지게 하였다.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
 <meta charset="utf-8">
 <meta http-equiv="cache-control" content="no-cache">
 <meta http-equiv="pragma" content="no-cache"> 
 <meta http-equiv="expires" content="0">
 <meta http-equiv="X-UA-Compatible" content="IE=10" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>webrtc</title>
</head>
<body>

<div id="console-container" >
    Hello world
</div>

</body>
</html>

 

접속을 하면 정상적으로 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)의 모습이다.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
 <meta charset="utf-8">
 <meta http-equiv="cache-control" content="no-cache">
 <meta http-equiv="pragma" content="no-cache"> 
 <meta http-equiv="expires" content="0">
 <meta http-equiv="X-UA-Compatible" content="IE=10" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Title</title>
</head>

<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>		


<body>

<p>
<div>
  <!-- 테스트용 인풋 박스 -->
  <input type="text" id="chat" >
  <input type="button" value='send' id="clicker">
</div><br><br>
</body>
</html>

<script type="application/javascript">

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;
}

</script>

 

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

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

 

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

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

 

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

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

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

web_rtc_.7z
0.00MB

 

 

반응형

'WEB-RTC' 카테고리의 다른 글

WEB-RTC 개발 준비  (0) 2019.10.13
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글