재밌네... ㅎㅎ
별도의 비표준 플러그인 없이, 웹에서 채팅을 이렇게 쉽게 구현할 수 있는 시대라니...
6년전, 웹 소켓에 대해 나름 정리한 적이 있다.
이미 그 시대는 오래전(?)에 도래했건만, 개인적으로 방치해 두다가, 어제 밤 문득...
웹 소켓과 node.js를 사용해서 채팅 샘플을 구현해 보고 싶다는 생각이 스쳐 지나갔다.
socket.io라는 자바스크립트 라이브러리가 존재한다더니, 이건 뭐.. 다른건 볼 필요도 없네.
socket.io는 Node.js 기반으로 소켓 통신이 가능하도록 해 주는 확장 라이브러리인데, HTML5의 정식표준인 WebSocket을 지원하지만, 미지원 환경에 대한 호환성을 위해 Comet 같은 기술도 하나의 API로 추상화 시킨 양방향 통신 라이브러리이다.
socket.io는 WebSocket이 지원되지 않는 환경에서 실시간 양방향 통신을 구현하기 위해 다음과 같은 fallback 기술을 사용하고 있다.
- FlashSocket, AJAX Long Polling, AJAX Multi part Streaming, IFrame, JSONP Polling
기본적으로 Node.js 설치해 주고, express와 socket.io를 npm을 통해 다음과 같이 설치한다.
- npm install express
- npm install socket.io
이제 환경 설정은 끝이다. 자바스크립트 기반 개발환경은 이렇듯 심플하다. 내가 좋아하는 이유 중 주요한 팩터이다.
* socket.io를 이용한 웹 채팅 구현하기
먼저 다음과 같은 3개의 파일을 준비한다.
1. chatServer.js
- 채팅 서버 역할을 하는 자바스크립트 파일로, Node.JS에 의해 호스팅되며 socket.io 라이브러리를 통해 소켓 서버를 구현한다. 또한 부가적으로 http 리소스 요청에도 응답할 수 있도록 한다.
2. chatClient.js
- 채팅 서버와 통신을 하는 클아이언트 자바스크립트 파일로, 역시 socket.io 라이브러리를 사용하며 채팅을 위한 간단한 DOM 조작을 수행한다.
3. chatClient.html
- chatClient.js가 정의된 html 파일이며, 채팅창과 텍스트 박스로 간단히 구성된 뷰를 제공한다.
먼저 chatServer.js 파일의 코드부터 보자.
var url = require("url");
//루트에 대한 get 요청에 응답
app.get("/", function(req, res){
console.log("get:chatClient.html");
//최초 루트 get 요청에 대해, 서버에 존재하는 chatClient.html 파일 전송
res.sendFile("chatClient.html", {root: __dirname});
});
//기타 웹 리소스 요청에 응답
app.use(function(req, res){
var fileName = url.parse(req.url).pathname.replace("/","");
res.sendFile(fileName, {root: __dirname});
console.log("use:", fileName);
});
//http 서버 생성
var server = require('http').createServer(app);
server.listen(3000);
console.log("listening at http://127.0.0.1:3000...");
//클로저를 사용해, private한 유니크 id를 만든다
var uniqueID = (function(){
var id = 0;
return function(){ return id++; };
})();
//서버 소켓 생성
var socket = require('socket.io').listen(server);
//소켓 Connection 이벤트 함수
socket.sockets.on('connection', function(client){
//클라이언트 고유값 생성
var clientID = uniqueID();
console.log('Connection: '+ clientID);
//서버 receive 이벤트 함수(클라이언트에서 호출 할 이벤트)
client.on('serverReceiver', function(value){
//클라이언트 이베트 호출
socket.sockets.emit('clientReceiver', {clientID: clientID, message: value});
});
});
다음으로 chatClient.js 소스이다.
//클라이언트 소켓 생성
var socket = io.connect('ws://127.0.0.1:3000');
//DOM 참조
var div = document.getElementById('message');
var txt = document.getElementById('txtChat');
//텍스트 박스에 포커스 주기
txt.focus();
//텍스트 박스에 이벤트 바인딩
txt.onkeydown = sendMessage.bind(this);
function sendMessage(event){
if(event.keyCode == 13){
//메세지 입력 여부 체크
var message = event.target.value;
if(message){
//소켓서버 함수 호출
socket.emit('serverReceiver', message);
//텍스트박스 초기화
txt.value = '';
}
}
};
//클라이언트 receive 이벤트 함수(서버에서 호출할 이벤트)
socket.on('clientReceiver', function(data){
//console.log('서버에서 전송:', data);
//채팅창에 메세지 출력하기
var message = '['+ data.clientID + '님의 말' + '] ' + data.message;
div.innerText += message + '\r\n';
//채팅창 스크롤바 내리기
div.scrollTop = div.scrollHeight;
});
};
마지막으로 chatClient.html 파일이다.
<script src="/socket.io/socket.io.js"></script>
<div id="message" style="background-color:#F5F5F5; width:400px; height:200px; OVERFLOW-Y:auto; word-wrap: break-word"></div>
<div id="chatInput">
메시지를 입력하세요 <input type='text' id='txtChat' name="txtChat">
</div>
* 실행흐름
1) 서버 실행
- Node의 쉘기능을 이용해 다음과 같이 chatServer.js를 실행한다. 실행하면 다음 그림과 같이 console 로그가 프롬프트 창에 찍힌다.
2) 클라이언트 실행
- 클라이언트에서는 단순히 브라우저로 지정된 url로 접근하기만 하면 된다.
브라우저로 chatServer.js 서버로 접속하면, 루트 get요청(http://127.0.0.1:3000)에 따른 chatClient.html 파일이 클라이언트로 다운로드 되고, 이 HTML파일이 브라우저에서 실행되면서 chatClient.js 파일에 대한 요청이 다시 이뤄져 자바스크립트 코드가 다운로드 되고 실행된다. 이 클라이언트 자바스크립트가 실행되어 소켓서버와 클라이언트는 서로 연결이 이뤄진다.
다음 그림은 브라우저에서 해당 url로 접근했을 때 서버측 로그화면이다.
* 결과화면
- 총 4개의 사용자가 접근하는 시나리오로 가정하여, 4개의 브라우저를 동시에 사용한다. 각 브라우저에서 해당 url로 접근하고 각자 채팅을 해 본다. 이때 각 클라이언트 구분은 서버측 코드에서처럼 임의의 순처적 고유값을 부여한 숫자로 사용한다.
다음 화면은 브라우저 4개를 띄우고, 채팅을 해본 모습니다. 혼자놀기에 좋다 ㅡ,ㅡ;
지금까지 알아본 샘플 채팅은 채팅 구현을 위한 가장 기본적이면서도 필수적으로 구현되어야 하는 것들만 다뤘다. 실제 업무에서 채팅을 구현한다면 성능과 안정성 등을 위해 다양한 방어코드, 추가기능 코드, 최적화 기법 등의 추가 작업이 필요할 것이다.
기본적인 흐름과 코드를 알았으니, 살을 붙여 나가면 될 일이다.
'모바일 > Javascript' 카테고리의 다른 글
[Node.js] CORS 설정(Cross Domain 요청 허용) (0) | 2016.07.15 |
---|---|
[AngularJS] REST API 통신(with Node.js) (0) | 2016.07.15 |
[AngularJS] Route (0) | 2016.07.14 |
[AngularJS] Directive (0) | 2016.07.13 |
[AngularJS] $scope과 controller-as 문법 (0) | 2016.07.12 |