블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2013. 1. 30. 16:03 NodeJS/Prototyping

한개의 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 안에 모듈 설치 디렉토리 생성

[mongodb@localhost mydomain.com]$ ll
total 20
drwxrwxr-x. 4 mongodb mongodb 4096 Feb  1 23:17 app
-rw-rw-r--. 1 mongodb mongodb 1109 Feb  1 23:17 app.js
drwxrwxr-x. 7 mongodb mongodb 4096 Feb  2 19:49 node_modules
-rw-rw-r--. 1 mongodb mongodb  590 Feb  1 23:17 package.json
drwxrwxr-x. 2 mongodb mongodb 4096 Feb  1 23:17 subdomains

//////////////////////////////////////////////////////
// sub1/sub2 도메인에 jade, stylus, express 설치 
// (socket.io는 mydomain에만 설치됨)
$ cd ../sub1.mydomain.com
$ npm install -d 
... 중략 ...
npm info prepublish sub.socket.io@1.0.0
jade@0.28.1 node_modules/jade
stylus@0.32.0 node_modules/stylus
express@2.5.8 node_modules/express


  -  /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

  - Express.js Virtual Host 설정

  - 원문과 동일한 socket.io 인스턴스 한개와 Virtual Host 를 통한 SubDomain 공유에 대한 동일 예제


posted by 윤영식
2013. 1. 29. 21:57 NodeJS/Prototyping

Node.js를 설치하고 MongoDB를 사용하여 REST API를 만들어보자. native MongoDB driver를 사용하며 REST API를 쉽게 만들기 위하여 Node.js의 웹애플리케이션 프레임워크인 Express를 이용한다. 원문의 내용을 보고 수행한 결과를 요약한다 



1) Node.js 설치 

  - http://nodejs.org/dist/  : 사이트에서 최신 버전을 선택하여 다운로드한다 

  - 예) linux 

[mongodb@localhost ~]$ wget http://nodejs.org/dist/v0.9.8/node-v0.9.8-linux-x86.tar.gz 

--2013-02-01 21:24:48--  http://nodejs.org/dist/v0.9.8/node-v0.9.8-linux-x86.tar.gz

Resolving nodejs.org... 165.225.133.150

Connecting to nodejs.org|165.225.133.150|:80... connected.

HTTP request sent, awaiting response... 200 OK

Length: 4491882 (4.3M) [application/octet-stream]

Saving to: “node-v0.9.8-linux-x86.tar.gz”


100%[=========================================================>] 4,491,882    284K/s   in 17s     


2013-02-01 21:25:07 (263 KB/s) - “node-v0.9.8-linux-x86.tar.gz” saved [4491882/4491882]


[mongodb@localhost ~]$ ls

aggregation  mongo  mongod  mongodb  mongofiles  mongos  node-v0.9.8-linux-x86.tar.gz  shard

[mongodb@localhost ~]$ tar zxf node-v0.9.8-linux-x86.tar.gz

[mongodb@localhost ~]$ ls

aggregation  mongod   mongofiles  node-v0.9.8-linux-x86         shard

mongo        mongodb  mongos      node-v0.9.8-linux-x86.tar.gz

[mongodb@localhost ~]$ rm node-v0.9.8-linux-x86.tar.gz

[mongodb@localhost ~]$ mv node-v0.9.8-linux-x86 node-v0.9.8

[mongodb@localhost ~]$ ls

aggregation  mongo  mongod  mongodb  mongofiles  mongos  node-v0.9.8  shard

[mongodb@localhost ~]$ cd node-v0.9.8/

[mongodb@localhost node-v0.9.8]$ cd bin

[mongodb@localhost bin]$ ./node -v

v0.9.8


2) Node.js 수행하기 

  - 적당한 디렉토리에 nodecellar 디렉토리 만듦

  - nodecellar 안에 server.js 파일 생성

  - server.js 코딩 

////////////////////////////////////////////////
// server.js
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(3000, '127.0.0.1');
console.log('Server running at http://127.0.0.1:3000/');


  - server.js 수행하고 브라우져에서 http://127.0.0.1:3000/ 호출 

[mongodb@localhost ~]$ cd nodecellar/

[mongodb@localhost nodecellar]$ node server.js

Server running at http://127.0.0.1:3000/



3) Express 설치하기 

  - Node.js의 Web Application Framework 이고, REST API 생성을 쉽게 해준다 

  - nodecellar 디렉토리안에 package.json 파일을 만들어서 Node.js가 의존하는 모듈을 정의한다 

////////////////////////////////////////////
// package.json
{
    "name": "wine-cellar",
    "description": "Wine Cellar Application",
    "version": "0.0.1",
    "private": true,
    "dependencies": {
        "express": "3.x"
    }
}

  - express 설치하기 

// package.json의 의존관계 모듈을 읽어서 자동 설치해 준다 

[mongodb@localhost nodecellar]$ npm install

npm WARN package.json wine-cellar@0.0.1 No README.md file found!

npm http GET https://registry.npmjs.org/express

npm http 200 https://registry.npmjs.org/express

npm http GET https://registry.npmjs.org/express/-/express-3.1.0.tgz

... 중략 ...
express@3.1.0 node_modules/express
├── methods@0.0.1
├── fresh@0.1.0
├── range-parser@0.0.4
├── cookie-signature@0.0.1
├── buffer-crc32@0.1.1
├── cookie@0.0.5
├── commander@0.6.1
├── debug@0.7.0
├── mkdirp@0.3.3
├── send@0.1.0 (mime@1.2.6)
└── connect@2.7.2 (pause@0.0.1, bytes@0.1.0, formidable@1.0.11, qs@0.5.1)



4) server.js를 Express 형식으로 바꾸기 

  - express 프레임워크를 이용하여 HTTP Listener를 바꾼다

////////////////////////////////////////////
// server.js
var express = require('express');
 var app = express();
 
app.get('/wines', function(req, res) {
    res.send([{name:'wine1'}, {name:'wine2'}]);
});
app.get('/wines/:id', function(req, res) {
    res.send({id:req.params.id, name: "The Name", description: "description"});
});
 
app.listen(3000);
console.log('Express Listening on port 3000...');

  - express 실행

[mongodb@localhost nodecellar]$ node server

Express Listening on port 3000...


  - 브라우져 호출하기 

    + 전체 wine들 

  

    + 1번 wine 내역 

  


5) Node.js에서 Controller로써 routes를 만들기 

  - nodecellar 디렉토리 밑으로 routes 폴더를 만든다 

  - routes 밑에 모듈로 wines.js 를 만든다 

////////////////////////////////////////////
// routes 디렉토리 밑의 wines.js
exports.findAll = function(req, res) {
    res.send([{name:'wine1'}, {name:'wine2'}, {name:'wine3'}]);
};
 
exports.findById = function(req, res) {
    res.send({id:req.params.id, name: "The Name", description: "description"});
};


  - server.js 파일에서 wines.js 모듈을 로딩하게 한다. 그리고 다시 브라우져로 호출한다 

////////////////////////////////////////////
// server.js에서 wines.js 모듈 로딩
var express = require('express'),
    wines = require('./routes/wines');
var app = express();
 
app.get('/wines', wines.findAll);
app.get('/wines/:id', wines.findById);
 
app.listen(3000);
console.log('Express Listening on port 3000...');


6) MongoDB Driver 설치하기 

  - MongoDB는 설치되어 있다고 가정한다 (참조)

  - 여기서는 native Node.js driver를 사용한다

  - mongodb driver 설치하기 

[mongodb@localhost nodecellar]$ npm install mongodb

npm WARN package.json wine-cellar@0.0.1 No README.md file found!

npm http GET https://registry.npmjs.org/mongodb

...  중략 ...

npm http GET https://registry.npmjs.org/bson/-/bson-0.1.6.tgz

... 중략 ...

node-gyp clean

node-gyp configure build

gyp http GET http://nodejs.org/dist/v0.9.8/node-v0.9.8.tar.gz

gyp http 200 http://nodejs.org/dist/v0.9.8/node-v0.9.8.tar.gz

make[1]: Entering directory `/home/mongodb/nodecellar/node_modules/mongodb/node_modules/bson/build'

  CXX(target) Release/obj.target/bson/ext/bson.o

  SOLINK_MODULE(target) Release/obj.target/bson.node

  SOLINK_MODULE(target) Release/obj.target/bson.node: Finished

  COPY Release/bson.node

make[1]: Leaving directory `/home/mongodb/nodecellar/node_modules/mongodb/node_modules/bson/build'

child process exited with code 0

mongodb@1.2.11 node_modules/mongodb

└── bson@0.1.6



7) REST API 정의하기 

  - 호출 내역 

    + GET: 전체 wine 목록

    + GET: id로 선택된 wine 정보얻기 

    + POST: 새로운 wine 생성

    + PUT: id로 선택된 wine 정보갱신

    + DELETE: id로 선택된 wine 삭제하기 

  

  

  - server.js에서 wines.js를 확장한 메소드를 추가한다 

  - wines.js 안에 MongoDB 코드로 변경하기 



8) MongoDB 와 Node.js 수행하고 Testing 하기 

  - MongoDB는 default port로 수행한다 

[mongodb@localhost ~]$ ./mongod --dbpath /home/mongodb/aggregation

... 중략 ...

Fri Feb  1 22:30:46 [initandlisten] options: { dbpath: "/home/mongodb/aggregation" }

Fri Feb  1 22:30:46 [initandlisten] Unable to check for journal files due to: boost::filesystem::basic_directory_iterator constructor: No such file or directory: "/home/mongodb/aggregation/journal"

Fri Feb  1 22:30:46 [initandlisten] couldn't unlink socket file /tmp/mongodb-27017.sockerrno:1 Operation not permitted skipping

Fri Feb  1 22:30:46 [initandlisten] waiting for connections on port 27017

Fri Feb  1 22:30:46 [websvr] admin web console waiting for connections on port 28017



  - Node.js 수행하기 

     + MongoDB의 기본 port 27017 로 접근한다 

[mongodb@localhost nodecellar]$ node server

========================================================================================

=  Please ensure that you set the default write concern for the database by setting    =

=   one of the options                                                                 =

=                                                                                      =

=     w: (value of > -1 or the string 'majority'), where < 1 means                     =

=        no write acknowlegement                                                       =

=     journal: true/false, wait for flush to journal before acknowlegement             =

=     fsync: true/false, wait for flush to file system before acknowlegement           =

=                                                                                      =

=  For backward compatibility safe is still supported and                              =

=   allows values of [true | false | {j:true} | {w:n, wtimeout:n} | {fsync:true}]      =

=   the default value is false which means the driver receives does not                =

=   return the information of the success/error of the insert/update/remove            =

=                                                                                      =

=   ex: new Db(new Server('localhost', 27017), {safe:false})                           =

=                                                                                      =

=   http://www.mongodb.org/display/DOCS/getLastError+Command                           =

=                                                                                      =

=  The default of no acknowlegement will change in the very near future                =

=                                                                                      =

=  This message will disappear when the default safe is set on the driver Db           =

========================================================================================

Express Listening on port 3000...

Connected to 'winedb' database


  - curl을 수행한다 

/////////////////////////////////////////

// POST를 통하여 신규 wine을 생성한다

[mongodb@localhost ~]$ curl -i -X POST -H 'Content-Type: application/json' -d '{"name": "New Wine", "year": "2009"}' http://localhost:3000/wines

HTTP/1.1 200 OK

X-Powered-By: Express

Content-Type: application/json; charset=utf-8

Content-Length: 79

Date: Sat, 02 Feb 2013 06:38:49 GMT

Connection: keep-alive


{

  "name": "New Wine",

  "year": "2009",

  "_id": "510cb4798859a9b51d000001"


/////////////////////////////////////////

// MongoDb 확인 

[mongodb@localhost ~]$ mongo

MongoDB shell version: 2.2.2

connecting to: test

> show dbs

dowonDB 0.03125GB

local (empty)

winedb 0.0625GB

> use winedb

switched to db winedb

> show collections

system.indexes

wines

> db.wines.find()

{ "name" : "New Wine", "year" : "2009", "_id" : ObjectId("510cb4798859a9b51d000001") }


/////////////////////////////////////////

// GET 명령 수행하여 정보 조회

// wine 목록을 얻어온다.

[mongodb@localhost ~]$ curl -i -X GET http://localhost:3000/wines

HTTP/1.1 200 OK

X-Powered-By: Express

Content-Type: application/json; charset=utf-8

Content-Length: 93

Date: Sat, 02 Feb 2013 06:41:37 GMT

Connection: keep-alive


[

  {

    "name": "New Wine",

    "year": "2009",

    "_id": "510cb4798859a9b51d000001"

  }

]


// 특정 wine 조회. _id를 넣어준다 

[mongodb@localhost ~]$ curl -i -X GET http://localhost:3000/wines/510cb4798859a9b51d000001

HTTP/1.1 200 OK

X-Powered-By: Express

Content-Type: application/json; charset=utf-8

Content-Length: 79

Date: Sat, 02 Feb 2013 06:42:14 GMT

Connection: keep-alive


{

  "name": "New Wine",

  "year": "2009",

  "_id": "510cb4798859a9b51d000001"



/////////////////////////////////////////

// PUT 명령 수행하여 정보 수정 

[mongodb@localhost ~]$ curl -i -X PUT -H 'Content-Type: application/json' -d '{"name": "New Wine", "year": "2010"}' http://localhost:3000/wines/510cb4798859a9b51d000001
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 42
Date: Sat, 02 Feb 2013 06:44:00 GMT
Connection: keep-alive

{
  "name": "New Wine",
  "year": "2010"


/////////////////////////////////////////

// DELETE 명령 수행하여 정보 삭제

[mongodb@localhost ~]$ curl -i -X DELETE http://localhost:3000/wines/510cb4798859a9b51d000001
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 2
Date: Sat, 02 Feb 2013 06:46:22 GMT
Connection: keep-alive

/////////////////////////////////////////

// MongoDb 확인 

[mongodb@localhost ~]$ mongo
MongoDB shell version: 2.2.2
connecting to: test
> use winedb
switched to db winedb
> show collections
system.indexes
wines
> db.wines.find()    <=== 데이터가 삭제되어 없음 



<참조>

  - 원문 : Creating a REST API using Node.js, Express, and MongoDB

  - 참조 

    + https://speakerdeck.com/jakobmattsson/writing-restful-web-services-using-nodejs

    + Node.js 설치하기

    + MongoDB 설치하기

  - 심화 : Backbone.js 와 Bootstrap, Node.js로 만들기 

posted by 윤영식
2012. 12. 22. 17:42 NodeJS/Prototyping

socket.io를 이용하여 간단한 chatting 애플리케이션을 만들어 보자 


* 참조 : socket.io이용하여 chat 구현하기


> Express를 통하여 chat 컨텍스트를 만든다 (참조)

express chat


> app.js 에 socket.io를 위한 /chat 네임스페이스를 설정하고(jade이용), socket.io에 대하여 설정한다

// declaration

var express = require('express');

var app = express()

    , http = require('http').createServer(app)

    , io = require('socket.io').listen(http)

    , routes = require('./routes')

    , user = require('./routes/user')

    , chat = require('./routes/chat')

    , path = require('path');


app.get('/chat', chat.list);


// http listen

http.listen(app.get('port'), function(){

    console.log("Express server listening on port " + app.get('port'));

});


// socket connection event on

var chat = io

    .of('/chat')

    .on('connection', function(socket) {  // /chat uri로 접속이 들어오는 이벤트 처리 

        console.log('>>> chat server connection');


        socket.on('msg', function(data) { // msg 이벤트 처리 

            console.log('>>> data : ' + data.name + ', ' + data.msg);

            chat.emit('new', data); // new 이벤트를 발행하여 data를 다시 클라이언트들에게 전송 

        });

})


> jade 관련 파일 : chat.js 와 chat.jade 

// /routes 디렉토리의 chat.js 파일

exports.list = function(req, res){

    res.render('chat', { title: 'Chatting Example' });

};


//  /views 디렉토리의 chat.jade 파일

doctype 5

html

  head

    title= title

    link(rel='stylesheet', href='/stylesheets/style.css')

    script(src='/socket.io/socket.io.js')

    script(src='http://code.jquery.com/jquery-1.8.3.min.js')

    script(src='chat_module.js')

  body

    h1= title

    div#wrapper

        div#messages  // chat 메세지가 찍힌다 

        div.nic

            input#name(name='name', type='text')  // 이름 입력 창

        div

        textarea#message  // 메세지 입력 창

        br

        input#send(type='submit', value='Send')

    // chat_module.js에서 Chat 오브젝트를 초기화 한다 

    script

        $(document).ready(function() {

            Chat.initialize('/chat');

        });


> chat_module.js 안에 로직을 담는다 : 해당 모듈은 express의 public 디렉토리 밑에 놓는다 (즉시 실행 함수로 만듦)

(function() {

    window.Chat = {

      socket : null,


     // 초기화 시에 /chat uri 네임스페이스를 넣어주었다 

      initialize : function(socketURL) {

          console.log('step1 socketURL : %s', socketURL);

          this.socket = io.connect(socketURL);


          console.log('step2 conneciton ok : %s ', this.socket);


   // send 버튼을 누를 경우 실행 

          $('#send').click(function() {

              Chat.send();

          });


    // textarea 메세지 입력하고 enter key 칠 경우 

          $('#message').keyup(function(evt) {

             if((evt.keyCode || evt.which) == 13) {

                 Chat.send();

                 return false;

             }

          });


          // 서버로 부터 new 이벤트가 오면 메세지를 추가하는 add 콜백 설정  

          this.socket.on('new', this.add);

      },


      // 서버로 부터 발행된 new 이벤트 처리하는 펑션

      add : function(data) {

          console.log('add message : %s', data.name +', '+ data.msg);

          var name = data.name || 'anonymous';

          var msg = $('<div class="msg"></div>')

              .append('<span class="name">' + name + '</span>: ')

              .append('<span class="text">' + data.msg + '</span>');

          console.log('add html : %s', msg);


          $('#messages').append(msg).animate({scrollTop: $('#messages').prop('scrollHeight')}, 0);

      },


      // 메세지 넣고 send 버튼을 클릭할 때 수행하는 펑션 

      send : function() {

          console.log('sending message : %s', $('#name').val() +', '+ $('#message').val());

          this.socket.emit('msg', {

              name: $('#name').val(),

              msg: $('#message').val()

          });


          $('#message').val('');

      }

    };

}());



> node app 명령으로 Node 서버를 실행시킨 후 브라우저로 호출한다 (http://localhost:3000/chat)

youngsik과 dowon 끼리 대화하는 것을 서버가 전송하고 있다 


* Express + Jade + Socket.io 프로젝트 파일 전체  

chat.zip


* js 파일이 변경될 때 마다 Node.js를 restart 하고 싶지 않다면 supervisor를 사용한다 

posted by 윤영식
2012. 12. 22. 14:46 NodeJS/Prototyping

Node.js에서 Express.js를 사용하고 템플릿 엔진은 Jade를 사용한다. 이때 socket.io를 간단히 테스트 해보자 


> 먼저 Socket.io 모듈를 설치한다 (물론 express 모듈도 사전 설치되었다 가정한다)

npm install socket.io


> Express.js를 통하여 만들고자 하는 컨텍스트를 만든다

express day3


> day3 디렉토리로 이동을 하면 app.js 파일이 있고 해당 파일안에 socket.io 모듈를 넣고 http 모듈과 체인닝을 해준다. 그리고 jade 설정이 되어 있는 socketio.js 모듈을 로딩한다 

// app.js 파일 상단 코딩

// 기존 코드 

var express = require('express')

  , routes = require('./routes')  // index.js 파일 

  , user = require('./routes/user') // user.js 파일 

  , dowon = require('./routes/dowon')// dowon.js 파일 

  , http = require('http')

  , path = require('path');


// 변경 코드 

var express = require('express');

var app = express()

  , http = require('http').createServer(app)   

  , io = require('socket.io').listen(http)  // http 모듈을 socket.io 모듈과 체인닝함 

  , routes = require('./routes')

  , user = require('./routes/user')

  , socketio = require('./routes/socketio') // socketio.js 파일 로딩 

  , path = require('path');


> url rout 설정을 해줌 for jade

// url route

app.get('/', routes.index);

app.get('/users', user.list);

app.get('/socketio', socketio.io); //  브라우져에서 /socketio 호출하면 socketio 모듈의 io exports명칭의 펑션을 호출한다


> socketio.jade 파일을 만들어서 views 디렉토리에 놓는다 

// socketio.jade 파일 내역

doctype 5

html

  head

    title= title

    link(rel='stylesheet', href='/stylesheets/style.css')

    script(src='/socket.io/socket.io.js')

    script(src='http://code.jquery.com/jquery-1.8.3.min.js')

    script

        $(function() {

            var ws = io.connect();  // node에서 수행한 app.js의 socket.io listen으로 연결


            ws.emit('server_1');  // 서버쪽으로 server_1 이벤트 발행

            ws.on('client_1', function(msg) {  // 서버로부터 온 client_1 이벤트 처리 

                $('#container').html(msg);

            });

        });

  body

    h1= title

    div#container


> app.js 파일안에 socket.io 서버 코딩을 한다

// socket on

io.sockets.on('connection', function(socket) {

    console.log('server connection');


    socket.on('server_1', function(data) { // 클라이언트로 부터 온 server_1 이벤트 처리

        if(data != undefined) {

            console.log('>>>>>' + data);

        }


        var msg = 'hi youngsik';

        socket.emit('client_1', msg); // 클라이언트쪽으로 client_1 이벤트 발행

    });

});


> 브라우저에서 호출한다 그러면 잠시후 브라우져에서 "hi youngsik" 메세지가 div(id=container)에 뿌려진다


* 테스트 전체 파일

express_socketio.zip


* Socket.io GitHub : 자세한 사용 설명 보기

posted by 윤영식
prev 1 next