한개의 Socket.io 인스턴스를 공유하여 3개의 독립적인 채팅 서버를 운영하는 방법과 Express.js 사용시 virtual host를 설정하여 sub domain을 만드는 방법을 알아본다.
1. 가정
- mydomain.com / sub1.mydomain.com / sub2.mydomain.com 의 서로 독립적인 채팅서버 운영
- socket.io 인스턴스는 하나만 사용하여 공유함
2. GitHub에서 소스 다운로드
- git 기본 설치 되었음을 가정한다 (참조)
- 각 분리된 namespace에서 Chat 애플리케이션 3개의 인스턴스를 수행할 것이다
- 소스 설치하기
[mongodb@localhost ~]$ git clone git://github.com/braitsch/sub.socket.io.git socket-io-example
Initialized empty Git repository in /home/mongodb/socket-io-example/.git/
... 중략 ..
Resolving deltas: 100% (56/56), done.
[mongodb@localhost ~]$ cd socket-io-example/
[mongodb@localhost socket-io-example]$ pwd
/home/mongodb/socket-io-example
///////////////////////////////////////////
// 각 분리된 namespace 존재
[mongodb@localhost socket-io-example]$ ls
README.md
mydomain.com
sub1.mydomain.com
sub2.mydomain.com
3. mydomain.com의 app.js 와 mydomain.com/subdomain/sub1(2).js 소스이해
- Express 사용하기
// app.js
var exp = require('express');
var app = exp.createServer();
- socket.io Listen 설정 : 전역(gobal)으로 Socket.IO 인스턴스에 접근하도록 선언한다
// app.js
// create the single instance of socket.io that will be shared across all applications //
// 한개의 socket.io인스턴스를 생성하여 모든 애플리케이션간 공유한다
global.socket = require('socket.io').listen(app);
global.socket.set('log level', 1);
global.socket.set('transports', [ 'websocket', 'flashsocket', 'htmlfile', 'xhr-polling', 'jsonp-polling']);
- subdomain 만들기
+ virtual host로써 동작하는 subdomain 애플리케이션을 설정한다
// create subdomain applications //
app.use(exp.vhost('sub1.' + global.host, require('./subdomains/sub1')));
app.use(exp.vhost('sub2.' + global.host, require('./subdomains/sub2')));
- 모듈 로딩하면서 수행
// finally create this application, our root server //
// chat-socket.js 파일 모듈 로딩
require('./app/config')(app, exp);
require('./app/server/router')(app);
require('./app/server/modules/chat-socket');
- sub1(2).js 소스 : 채팅 커넥션과 메세지를 다루기위해 chat-socket을 포함한 Express 애플리케이션이다
var exp = require('express');
var app = exp.createServer();
app.root = global.root + '/sub1.mydomain.com';
require(app.root + '/app/config')(app, exp);
require(app.root + '/app/server/router')(app);
require(app.root + '/app/server/modules/chat-socket');
module.exports = app;
4. chat-socket.js 소스이해
- socket.io에 네임스페이스를 '/chat'으로 정의하기
// pwd : ./socket-io-example/mydomain.com/app/server/modules
module.exports = function()
{
// 랜덤하게 사용자 색깔 지정
var colors = ['#AE331F', '#D68434', '#116A9F', '#360B95', '#5F209E'];
// 사용자 커넥션 추적을 유지하기 위한 객체 생성
var connections = { };
// if you use socket.of(), you can set namespace.
// chat 네임스페이스 정의하고 connect 되면 수행할 펑션들 정의
global.socket.of('/chat').on('connection', function(socket) {
// give each connected user a random color so it's easier to tell them apart in the chat log //
// 채팅사용자가 준비상태
socket.on('user-ready', function(data) {
socket.name = data.name;
socket.color = data.color = colors[Math.floor(Math.random() * colors.length)];
brodcastMessage('user-ready', data);
});
// 메세지 전송하기
socket.on('user-message', function(data) {
data.color = socket.color;
brodcastMessage('user-message', data);
});
// 접속자 상태 전송
function dispatchStatus()
{
brodcastMessage('status', connections);
}
// 메세지 전송하기
function brodcastMessage(message, data)
{
// remove socket.emit if you don't want the sender to receive their own message //
socket.emit(message, data);
socket.broadcast.emit(message, data);
}
// soket.io 커넥션 끊길 때 호출
// handle connections & disconnections //
connections[socket.id] = {}; dispatchStatus();
socket.on('disconnect', function() {
delete connections[socket.id]; dispatchStatus();
brodcastMessage('user-disconnected', { name : socket.name, color : socket.color });
});
});
}();
- sub1.mydomain.com 에 대하여 네임스페이스를 틀리게 기술한다
global.socket.of('/chat-sub1').on('connection', function(socket) ...
- sub2.mydomain.com 에 대하여 네임스페이스를 틀리게 기술한다
global.socket.of('/chat-sub2').on('connection', function(socket) ...
5. index.js와 index.jade 소스이해
- index.jade 하단에 index.js 와 socket.io.js 포함
div.navbar.navbar-fixed-top
div.navbar-inner
div.container-fluid
ul.nav.pull-left
.brand Node.js & Socket.IO Chat Server
ul.nav.pull-right
li
a(href='#')#connected
#container
#send-message.well.span4
h2 Say Something
hr
label Your Name
input(type="text", name="name", id='name').span4
label Your Message
textarea(rows='6', name="msg", id='msg').span4
button#btn-send.btn.btn-primary
i.icon-pencil.icon-white
| Send it !
#messages.well.span4
h2 Conversation
hr
#incoming
script(src='/vendor/jquery.min.js')
script(src='/socket.io/socket.io.js')
script(src='/js/index.js')
- index.js 파일
$(document).ready(function() {
$('#msg').focus();
// give user a generic name to start //
// 사용자가 접속하면 랜덤 명칭을 설정한다
$('#name').val(Math.random().toFixed(8).toString().substr(2));
$('#btn-send').click(function(){ sendMessage(); })
$('#msg').keypress(function(e){ if (e.keyCode === 13) { sendMessage(); return false; } })
// initialize the socket connection to listen on the 'chat' namespace //
socket = io.connect('/chat');
socket.on('status', function (connections) {
var i=0; for (p in connections) i++;
var s = i > 1 ? ' are '+i+' People ' : ' is '+i+' Person ';
$('#connected').html('There '+s+' Currently Connected');
});
socket.on('user-ready', function (data) {
$('#incoming').append('<span class="shadow" style="color:'+data.color+'">'+data.name +' :: connected</span><br>');
autoScroll();
});
socket.on('user-message', function (data) {
$('#incoming').append('<span class="shadow" style="color:'+data.color+'">'+data.name +' :: '+ data.message+'</span><br>');
autoScroll();
});
socket.on('user-disconnected', function (data) {
$('#incoming').append('<span class="shadow" style="color:'+data.color+'">'+data.name +' :: disconnected</span><br>');
autoScroll();
});
// register the user's name with the socket connection on the server //
socket.emit('user-ready', {name : $('#name').val() });
var autoScroll = function() {
document.getElementById('incoming').scrollTop = document.getElementById('incoming').scrollHeight;
}
// 메세지 보내기
var sendMessage = function() {
socket.emit('user-message', {name : $('#name').val() , message : $('#msg').val() });
$('#msg').val('')
}
});
7. 채팅 서비스 설정하기
- 채팅 서비스에 대한 수행전에 필요한 모듈에 대해서 install 한다
///////////////////////////////////////////////////////////////
// mydomain.com 에 stylus, jade, express, socket.io 설치
// package.json 참조하여 설치함
$ cd mydomain.com
$ npm install -d
... 중략 ...
stylus@0.32.0 node_modules/stylus
jade@0.28.1 node_modules/jade
express@2.5.8 node_modules/express
socket.io@0.9.13 node_modules/socket.io
npm info ok
// mydomain.com 안에 모듈 설치 디렉토리 생성
- /etc/hosts 파일에 다음을 설정한다 : 브라우져에서 호출하기 위한 sub1, sub2 도메인을 설정한다
127.0.0.1 sub1.localhost
127.0.0.1 sub2.localhost
8. Chat Node Server 실행하기
- mydomain.com 디렉토리로 들어가서 Node를 실행한다
/home/mongodb/socket-io-example/mydomain.com
[mongodb@localhost mydomain.com]$ node app
info - socket.io started
Express server listening on port 8080 in development mode
- 브라우져 2개를 띄워서 http://localhost:8080 을 동일하게 실행한다
+ dowon 채팅창과 다른 브라우져창에서 try 명칭의 사용자가 들어왔다
+ socket.io를 통하여 채팅을 주고 받고 있다
- 브라우져 2개를 띄워서 http://sub1.localhost:8080 을 동일하게 실행한다 (http://sub2.localhost:8080 동일 수행함)
+ youngsik 채팅창과 다른 브라우져창에서 girl 명칭의 사용자가 들어왔다
+ mydomain.com의 동일한 socket.io를 통하여 채팅을 주고 받고 있다 (namespace만 틀릴 뿐이다)
<참조>
- 원문 : Building a Node.js Chat Application and Sharing Socket.IO Across Multiple Subdomains
- 소스 : https://github.com/braitsch/sub.socket.io
- 원문과 동일한 socket.io 인스턴스 한개와 Virtual Host 를 통한 SubDomain 공유에 대한 동일 예제
'NodeJS > Prototyping' 카테고리의 다른 글
[Node.js] Node.js, Express, MongoDB를 이용하여 REST API 만들기 (0) | 2013.01.29 |
---|---|
[Socket.io] Chatting 구현하기 (0) | 2012.12.22 |
[Socket.io] Express.js 에 Jade로 붙여서 보기 (0) | 2012.12.22 |