'socket.io'에 해당되는 글 2건

  1. 2011.11.02 Socket.io 설치 와 간단 사용
  2. 2011.11.02 websocket #4 (웹소켓의 한계) (1)

curl 설치

$ sudo apt-get install curl


npm 설치  (/usr/local 디렉토리에 저장하기 때문에 sudo가 반드시 필요하다)

$ curl http://npmjs.org/install.sh | sudo sh



socket.io 설치 (최신 버전 0.8.6 다운)

$ npm install socket.io
socket.io@0.8.6 ./node_modules/socket.io 
├── policyfile@0.0.4
├── redis@0.6.7
└── socket.io-client@0.8.6



현재 디렉토리 밑의 node_modules/socket.io 에 socket.io 모듈이 설치되어 있다.

<간단한 예제 실행>

# 서버 실행
서버 코드 작성

 var http = require("http"), 
    io = require("./node_modules/socket.io"),       
    server = http.createServer(function(req, res) {});   

server.listen(8000, null); 

var socket = io.listen(server); 
socket.on("connection", function(client) { 
client.on("message", function(msg) {
console.info("message : " + msg);
});  
client.on("disconnect", function() {
consoe.info("disconnected..");
});  
});

console.log('Server running at http://127.0.0.1:8000/');



서버 코드 실행

$ node socketio-server.js
   info  - socket.io started
Server running at http://127.0.0.1:8000/




# 클라이언트 실행


<html>
<head>

<script src="http://cdn.socket.io/stable/socket.io.js"></script>
<script>
var socket = new io.Socket('localhost',{
  port: 8000
});
socket.connect(); 


socket.on('connect',function() {
  alert('Client has connected to the server!');
});


socket.on('message',function(data) {
  alert('Received a message from the server!',data);
});

socket.on('disconnect',function() {
  alert('The client has disconnected!');
});

socket.on('error', function(msg) {
alert('error' + msg);
}

function sendMessageToServer(message) {
  socket.send(message);
}

</head>

</script>
<body>
test
</body>
</html>





# 서버 출력

브라우져에서 클라이언트 코드 실행하니.. 약간 문제가 발생했다. 


~$ node socketio-server.js
   info  - socket.io started
Server running at http://127.0.0.1:8000/
   info  - unhandled socket.io url
   warn  - unknown transport: "undefined"
   info  - unhandled socket.io url
   warn  - unknown transport: "undefined"
   info  - unhandled socket.io url
   warn  - unknown transport: "undefined"
   info  - unhandled socket.io url
   warn  - unknown transport: "undefined"
   info  - unhandled socket.io url
   warn  - unknown transport: "undefined"
   info  - unhandled socket.io url
   warn  - unknown transport: "undefined"


이상하다 싶어서 stack trace 확인했지만, 이상해...
내부에서 약간 꼬인듯. 새버전이라 그런가??

~$ sudo strace -p 10263
Process 10263 attached - interrupt to quit
waitpid(-1, 


 
 
이번엔 example의 chat 예제로 실행해본다. 


# 서버 실행

서버를 실행하니. express, stylus , nib모듈이 필요하다고 한다. 

$ node app.js

node.js:134
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
Error: Cannot find module 'express'
 


express 모듈과 stylus 모듈과 nib 모듈을 설치한다. 
 

$ npm install  express
express@2.5.0 ./node_modules/express 
├── mkdirp@0.0.7
├── mime@1.2.4
├── qs@0.3.1
└── connect@1.7.2

$ npm install stylus
stylus@0.19.0 ./node_modules/stylus 
├── mkdirp@0.0.7
├── growl@1.1.0
└── cssom@0.2.0
$ npm install nib
nib@0.2.0 ./node_modules/nib 



$ node app.js 
실행하고 http://localhost:3000/ 브라우저 요청을 날리니 ' Cannot find module 'jade'' 에러가 발생한다. 

jade모듈도 설치한다.
 

$ npm install jade
jade@0.16.4 ./node_modules/jade 
├── mkdirp@0.0.7
└── commander@0.2.1



서버를 실행한다. 

$ node app.js
   info  - socket.io started
   app listening on http://0.0.0.0:3000




브라우져에서 다음 주소로 연결한다. 
https://localhost:3000/





다른 서버에서도 접근하면 잘 동작되는 지 확인해 볼 수 있다. 




<어플리케이션을 OS 서비스로 등록 : service ... start >
root 권한이 필요하다. 

$ sudo npm install forever -g

....
forever@0.7.2 /usr/local/lib/node_modules/forever 
├── colors@0.5.1
├── async@0.1.15
├── mkdirp@0.0.7
├── pkginfo@0.2.2
├── portfinder@0.2.0
├── timespan@2.0.1
├── watch@0.3.3
├── minimatch@0.0.4
├── daemon@0.3.2
├── cliff@0.1.5 (eyes@0.1.6)
├── optimist@0.2.8 (wordwrap@0.0.2)
├── nconf@0.4.4 (ini@1.0.1)
├── dnode@0.8.2 (dnode-protocol@0.0.12 lazy@1.0.7 traverse@0.4.6 socket.io@0.6.18)
├── ps-tree@0.0.1 (parse-table@0.0.0)
├── winston@0.5.6 (eyes@0.1.6 stack-trace@0.0.6 loggly@0.3.9)
└── clip@0.1.6



서버를 실행해 본다. 
 

$ forever start app.js
info:   Running action: start
info:   Forever processing file: app.js


3000번 포트가 정상적으로 뜨는 지 확인한다. 

$ telnet localhost 3000
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.



더이상 OS 서비스로 사용하지 않기 위해서는 stop 파라미터를 사용한다. 


$ forever stop app.js
info:   Running action: stop
info:   Forever stopped process:
data:       uid  command script forever pid   logfile                             uptime       
[0] QrfB node    app.js 11334   11335 /home/xxx/.forever/QrfB.log 0:0:9:27.142 






<느낀점>
node.js 와 socket.io의 능력은 괜찮은 것 같다. 편하게 개발이 가능하고 쉽게 써먹을 만하다.
무척 가능성이 보인다는 장점이 있다. 


<소스>
내가 node.js나 socket.io 관련한 전문가가 아니라서, 

# app.js
app.js 소스를 보니. 진작 이거 보고 하나씩 설치할 것 그랬다는 생각이 들었다. 

var express = require('express')
  , stylus = require('stylus')
  , nib = require('nib')
  , sio = require('socket.io');

express가 서버 모듈이다. 

var app = express.createServer();
app.configure(function () {
...
}

app.get('/', function (req, res) {
  res.render('index', { layout: false });
});

app.listen(3000, function () {
  var addr = app.address();
  console.log('   app listening on http://' + addr.address + ':' + addr.port);
});


socket io로 express 서버를 감싼다. 
그리고, nicknames라고 해서 채팅방의 사용자를 저장하는 array를 둔다.

 var io = sio.listen(app)  
  , nicknames = {};

'connect'가 되면, user message를 받는다. 

io.sockets.on('connection', function (socket) {
  socket.on('user message', function (msg) {
    socket.broadcast.emit('user message', socket.nickname, msg);
  });


nickname에 대한 처리. 
  socket.on('nickname', function (nick, fn) {
    if (nicknames[nick]) {
      fn(true);
    } else {
      fn(false);
      nicknames[nick] = socket.nickname = nick;
      socket.broadcast.emit('announcement', nick + ' connected');
      io.sockets.emit('nicknames', nicknames);
    }
  });
 

'disconnect'가 되었을때를 위한 처리이다. 
  socket.on('disconnect', function () {
    if (!socket.nickname) return;

    delete nicknames[socket.nickname];
    socket.broadcast.emit('announcement', socket.nickname + ' disconnected');
    socket.broadcast.emit('nicknames', nicknames);

 

# index.jade
jade에 대해서 몰랐는데. 이렇게 접하게 되었다. 

doctype 5
html
  head
    link(href='/stylesheets/style.css', rel='stylesheet')
    script(src='http://code.jquery.com/jquery-1.6.1.min.js')
    script(src='/socket.io/socket.io.js')
    script
      // socket.io specific code
      var socket = io.connect();

      socket.on('connect', function () {
        $('#chat').addClass('connected');
      });

      socket.on('announcement', function (msg) {
        $('#lines').append($('<p>').append($('<em>').text(msg)));
      });

      socket.on('nicknames', function (nicknames) {
        $('#nicknames').empty().append($('<span>Online: </span>'));
        for (var i in nicknames) {
          $('#nicknames').append($('<b>').text(nicknames[i]));
        }
      });

      socket.on('user message', message);
      socket.on('reconnect', function () {
        $('#lines').remove();
        message('System', 'Reconnected to the server');
      });

      socket.on('reconnecting', function () {
        message('System', 'Attempting to re-connect to the server');
      });

      socket.on('error', function (e) {
        message('System', e ? e : 'A unknown error occurred');
      });

      function message (from, msg) {
        $('#lines').append($('<p>').append($('<b>').text(from), msg));
      }

      // dom manipulation
      $(function () {
        $('#set-nickname').submit(function (ev) {
          socket.emit('nickname', $('#nick').val(), function (set) {
            if (!set) {
              clear();
              return $('#chat').addClass('nickname-set');
            }
            $('#nickname-err').css('visibility', 'visible');
          });
          return false;
        });

        $('#send-message').submit(function () {
          message('me', $('#message').val());
          socket.emit('user message', $('#message').val());
          clear();
          $('#lines').get(0).scrollTop = 10000000;
          return false;
        });

        function clear () {
          $('#message').val('').focus();
        };
      });
  body
    #chat
      #nickname
        form.wrap#set-nickname
          p Please type in your nickname and press enter.
          input#nick
          p#nickname-err Nickname already in use
      #connecting
        .wrap Connecting to socket.io server
      #messages
        #nicknames
        #lines
      form#send-message
        input#message
        button Send



  


 

<부록>
만약..  chat 디렉토리 밑에 있는 app.js를 실행하니 에러가 난다.  음 이건 머냐?

$ node app.js

node.js:289
    var cwd = process.cwd();
                      ^
Error: No such file or directory
    at Function.resolveArgv0 (node.js:289:23)
    at startup (node.js:43:13)
    at node.js:448:3



해결방법 : shell에서 디렉토리에 문제가 있는지, 정상적인 파일 access인지  확인하고, 
다시 디렉토리로 접근하면 된다.

 
Posted by 김용환 '김용환'

websocket을 직접 해보니 브라우져 지원 여부를 확실히 한계가 있다는 게 느꼈다..
기존 언어에서 통신 관련 옵션을 지원했던 거라든가. 좀 더 명확한 api가 있으면 좋겠다는 생각을 했다. 


그래서 socket.io에 이런 내용이 없나 봤더니.. 좀 있다. 
http://socket.io/#announcement



  1. You need to think about how you encode and interpret messages.
  2. It's hard to achieve interoperability with 3rd-party code.
  3. Logic for "connecting" or "disconnecting" specific parts of the application are inexistent.
  4. Authentication, error-handling for different subsets of functionality introduce even more difficulties.

     

아웃사이더님이 잘 요약해주셨다. 한글자료이니 잘 참조하면 될듯 하다. 
http://blog.outsider.ne.kr/668

 

연결에 대해서 명확한 개념을 socket.io에 구현했다. 

Websocket 코드 
var a = new WebSocket();

a
.onmessage = function (msg) {
 
var msg = JSON.parse(msg);
 
if (msg.type == 'chat') {
   
Chat.handle(msg.data);
 
} else {
   
// do something else
 
}
};

namespace 관련해서 Socket.io 구현 코드  확실히 깔끔한 느낌이 있다. 

<script>
 
var chat = io.connect('/chat');
  chat
.on('message', function () {
   
// chat socket messages
 
});
  chat
.on('disconnect', function () {
   
// chat disconnect event
 
});

 
var news = io.connect('/news');
  news
.on('item', function () {
   
// a new `news` socket event is here
 
});
</script>

파라미터 (인코딩/디코딩)도 쉽다.  send 함수에서 emit 을 쓰면 api 의 유용성이 풍부해진다. 

// client-side
var socket = io.connect();
socket
.emit('set nickname', 'john', function (response) {
  console
.log(response);
});

// server-side
// …
socket
.on('set nickname', function (nick, fn) {
 
if (nick == 'rauchg') {
    fn
({ err: 'nickname in use' });
 
}
});

 

Room기능이 추가되었다.
소켓 내에서 room을 구분해서 쓸 수 있게 되었다. 
io.sockets.on('connection', function (socket) {
  socket
.join('a room');
  socket
.broadcast.to('a room').send('im here');
  io
.sockets.in('some other room').emit('hi');
});


역쉬 socket.io 에서 쓰는 이유가 있군.. websocket에 대해서 좀 더 쉽고 깔끔한 코드를 지원한다. 







'scribbling' 카테고리의 다른 글

윈도우 (window) 7 에서 xe + cubrid + xe 1.5.0.8 개발환경 셋팅  (0) 2011.11.04
Socket.io 설치 와 간단 사용  (0) 2011.11.02
websocket #4 (웹소켓의 한계)  (1) 2011.11.02
websocket #3  (0) 2011.10.31
websocket #2 (node.js 설치)  (1) 2011.10.31
websocket #1  (0) 2011.10.28
Posted by 김용환 '김용환'