Apache Con 2011 자료

scribbling 2011. 11. 15. 19:03

Apache Con 2011 을 다녀오신 분의 후기가 올라왔다.

http://tuning-java.com/447


그리고, 일부 자료는 올라와 있다..

http://lanyrd.com/2011/apachecon-north-america/schedule/


"제목"을 클릭하면, 오디오와 ppt를 다운받을 수 있다.

조만간에 http://na11.apachecon.com/ 에서 다운받을 수 있을 것이다..
Posted by '김용환'
,

전자기파 측정기 를 통해서 얻은 내용을 예쁘게 정리 했다.

(원글 :
http://knight76.tistory.com/entry/아두이노-전자파정확히-말하면-전자기파-측정기-EMF-Detector-소스-공유)



나의 전자기파 탐지기는 는 간단하게 다음과 같이 만들었습니다.




이 기기를 가지고 PC의 전원 플러그가 꽂혀 있는 멀티탭의 전원부위로 이동(10cm 미만 거리)시켰더니, 2 정도 출력됩니다.

(입력 수치의 아날로그 in을 1000으로 받았을 때, 얼마나 전류가 흘러가는 체크하는 것이라 숫자는 큰 의미없이 상대적으로 보시면 될 것 같습니다.)

 

전화기, 델 24인치 모니터, 삼성 싱크 마스터, 델 PC, 사내에 굴러 다니는 삼성/LG TV 는 이 기기로 전자기파를  검출하지 못했습니다.

그러나, 노트북의 경우는 조금 달랐습니다.노트북은 충전하느냐와 충전하지 않느냐에 따라서 좀 이슈가 있는데요.

 

충전하지 않는 노트북은 대 부분이 전자기파가 흐르지 않았습니다. 그러나 충전했을 때 전자기가파가 대부분 발생했습니다.

eeepc, 아소스, 애플, 델 노트북이 대부분 발생했으며, 애플 맥북, 에어의 제품이 가장 많이 발생했습니다. 플라스틱이든 알루미늄이든 저의 기기의 fnd가 3까지 올라가는 것을 볼 수 있었습니다. 약 5~10 cm 범위에 측정했으며, 노트북 접지를 하지 않았습니다.

노트북의 키보드쪽에서 가장 많이 발생되며 일부 노트북은 마우스까지도 전자기파가 나오더군요.

그리고, 특히 애플 어댑터의 경우 다른 노트북과 달리 꽤 많이 나오는 전자기파가 있었습니다.

 

소니 바이오 구형, 델 엘리트북은 충전해도 전자기파가 나오지 않았습니다.

 

그래서, 좀 더 정확한 정보를 위해서 모처에 전시되어 있는 노트북에 전자기파를 측정했습니다. .

삼성, LG 노트북을 제외하고 모든 노트북에서 전자기파가 측정되었습니다.

 

노트북의 경우는 많은 분들이 침대에서 머리 주변주쪽에 두고 많이 사용하기 때문에 이런 부분을 많이 고려해야 할 것 같습니다.

특히 임산부나 아이를 키우시는 분들은 전원 플러그 근처와 충전 노트북에는 멀리 하는 게 좋을 것 같습니다.

 

그 다음으로 테스트한 것은 아이폰, 아이패드, 갤럭시탭와 같은 핸드폰이었습니다.

예전에 스폰지에서 전화기가지고 달걀을 익히는 것을 본지라, 테스트를 했는데요. 저의 기기에서는 전혀 전자기파를 측정할 수 없었습니다. 아마도 내부에 전자기파 차단 처리를 한 것으로 생각되는데요.

전화할 때나, 충전할 때 전자기파가 의외로 발생하지 않아서 약간 놀랬습니다. 

 

마지막으로 사내에서 가장 많이 전자기파가 나오는 것을 하나 발견했는데요.

이 제품은 전원만 켜도 60cm (눈 짐작)에서부터 전자기파가 발생되고, 핵심에서 측정하면 3 정도로 나왔습니다. 바로 음이온이 나오는 H사의 이온파크 선풍기였습니다. 
음이온이 나온다고 하지만, 찜찜해서, 멀리해서 쓰고 있습니다.

 

Posted by '김용환'
,

리눅스에서 개발서버를 돌리지만, 로컬에서의 개발환경이 있어야 생산성을 확보할 수 있다.  


1. apmsetup 7 버전을 특정 위치에 설치한다.  (내 위치는 C:\APM_Setup)
http://www.apmsetup.com/

이 때 주의할 점은 잘 모르면, cubrid db를 반드시 설치해야 한다.
로컬 pc에 cubrid db를 설치안하면 cubrid 연동이 안되서 어제 고생좀 했는데. 그 이유는 바로 php_cubrid.dll 이 로딩되기 위해서는 의존하는 cubrid window version의 DB의 cascci.dll 파일이 있어야 한다. 이 파일은 cubrid db를 설치할 때 생성되는 거라, 인터넷에서는 다운받기 힘들다. 만약 cascci.dll 파일이 있으면 cubrid db를 설치안해도 된다. cascci.dll 파일을 apache가 설치된 경로의 bin 디렉토리나 window의 system32 디렉토리안에 두어야 한다. 

PHP Warning:  PHP Startup: Unable to load dynamic library 'c:\\APM_Setup\\Server\php5\\ext\\php_cubrid.dll' - %1\xc0\xba(\xb4\xc2) \xbf\xc3\xb9\xd9\xb8\xa5 Win32 \xc0\xc0\xbf\xeb \xc7\xc1\xb7\xce\xb1\xd7\xb7\xa5\xc0\xcc \xbe\xc6\xb4\xd5\xb4\xcf\xb4\xd9.\r\n in Unknown on line 0


http://www.cubrid.com/zbxe/56862
http://www.cubrid.com/zbxe/160377#comment_161268

그러면, apache-php  연동이 된다. apmsetup 모니터를 보고 mysql 데몬을 내린다.



C:\APM_Setup\php.ini 파일을 보면,  php cubrid interface dll 파일 (php_cubrid.dll
) 로딩에 대해서 주석이 되어 있다.

;extension=php_cubrid.dll

그리고,  C:\APM_Setup\Server\PHP5\ext 디렉토리에 dll 파일이 있는 지 확인한다.



2. php-cubird 연동

C:\APM_Setup\php.ini 파일을 보면,  php cubrid interface dll 파일(php_cubrid.dll
) 에 대한 주석을 해제한다.

extension=php_cubrid.dll


그리고, 아파치 재시작을 하고 나서, 다음 php 정보를 보는 화면에서 cubrid로 검색해본다.

http://127.0.0.1/?page=phpinfo



이러면 완전 ok


3. xe (express engine)를 설치한다.

http://www.xpressengine.com 에 접속해서 xe core를 다운받고 C:\APM_Setup 밑의 xe 디렉토리에 설치한다.

아파치 설정 파일 "C:\APM_Setup\Server\Apache\conf\httpd.conf" 파일에서

DocumentRoot "C:/APM_Setup/htdocs"  를

DocumentRoot "C:/APM_Setup/xe"  로 수정하고 아파치를 재시작한다.


4. xe를 설치한다.

http://localhost 에 접근한다.



cubrid db를 선택한다.



리눅스 서버에서 접속해서 db를 하나 생성한다.

/opt/cubrid/bin 디렉토리에서 cubrid createdb windowtest 하면 windowtest 라는 논리 db가 만들어진다.

그리고, vi /opt/cubrid/conf/cubrid.conf 파일에서 server=test,windowtest 를 수정하여 windowtest 라는 논리 db가 cubrid db가 런치될 때마다 접근할 수 있게 한다.

사용자를 추가한다.

$ csql -C -u dba test

csql> create user root password 'root'

csql> commit

csql> select * from db_user;
확인


새로만든 계정으로 접근해본다.

$ csql -C -u root

패스워드는 위에서 적은 root ...
이 정보를 가지고 xe 설정에 넣어주면 끝.


그리고, 다시 xe 설치 화면으로 돌아가서 진행하면 된다.






'scribbling' 카테고리의 다른 글

Apache Con 2011 자료  (0) 2011.11.15
전자기파 측정을 통해서 얻는 생활의 지혜  (0) 2011.11.07
Socket.io 설치 와 간단 사용  (0) 2011.11.02
websocket #4 (웹소켓의 한계)  (1) 2011.11.02
websocket #3  (0) 2011.10.31
Posted by '김용환'
,

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




브라우져에서 다음 주소로 연결한다. 
http://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 #3  (0) 2011.10.31
websocket #2 (node.js 설치)  (1) 2011.10.31
websocket #1  (0) 2011.10.28
Posted by '김용환'
,

websocket #3

scribbling 2011. 10. 31. 18:30

아래 스펙을 기준으로 삼아서 공부.
http://www.whatwg.org/specs/web-socket-protocol/

키포인트는 바로 아래 헤더이다. 나머지 secure 한 부분이 있긴 하지만...

Connection : Upgrade
Upgrade:WebSocket


통신은 이렇게 한다. http handshake 하고 나서, 데이터는 시작을 알리는 헤더 0x00 정보 다음와 마지막을 의미하는 0xff 사이에 두어 통신한다. 그리고, 0x00 0xff 는 tcp close를 의미한다. 

내 생각엔  handshake와 통신 주고받는 법, 끊기.. 이게 websocket의 다인것 같다.. 
 

(참조 : http://warmcat.com/_wp/2010/11/01/libwebsockets-html5-websocket-server-library-in-c/)
 


웹 브라우져가 언제든지 소켓처럼 쓸 수 있다. 

(참조 : http://java.sys-con.com/node/1315473)


 


특별히 대단한 기술은 아지만, 다양한 사람들이 모여 하나의 spec를 정하고 이에 맞게 구현하고 있다는 점에서 인정해야 할 것 같다. 생각보다 단순해서 놀랬음.. ^^


참조 : http://cometdaily.com/2008/07/04/html5-websocket/

Orbited is a Web Firewall


 

'scribbling' 카테고리의 다른 글

Socket.io 설치 와 간단 사용  (0) 2011.11.02
websocket #4 (웹소켓의 한계)  (1) 2011.11.02
websocket #2 (node.js 설치)  (1) 2011.10.31
websocket #1  (0) 2011.10.28
Comet에 대한 일반론  (0) 2011.10.28
Posted by '김용환'
,

websocket 요청 하나 만들려고 서버를 무엇을 쓸려고 하나 고민이 된다..
netty, jetty, glassfish, grizzly, node.js 중에. 그냥 node.js로 선택해야 겠다는 생각이 든다..

자바보다는 js~ ㅎㅎ
이번 기회에 node.js도 배울 수 있겠다.


리눅스 OS(ubuntu) 에서 http://nodejs.org/#download 에 접속하고, 가장 최신인 0.4.12를 다운받는다. 


 Download

git repo

2011.09.15 v0.4.12 (stable)

node-v0.4.12.tar.gz Source Code
Documentation




 ./configure 명령을 내린다. 그러나 에러가 난다. 

 ./configure  
Checking for program g++ or c++          : not found 
Checking for program icpc                : not found 
Checking for program c++                 : not found 
/home/google/node-v0.4.12/wscript:232: error: could not configure a cxx compiler!



build-essential 패키지를 설치하니 문제가 사라진다.

sudo aptitude install build-essential 




./configure 명령을 내리면 잘 되는지 확인할 수 있다. 

$ ./configure
Checking for program g++ or c++          : /usr/bin/g++ 
Checking for program cpp                 : /usr/bin/cpp 
Checking for program ar                  : /usr/bin/ar 
Checking for program ranlib              : /usr/bin/ranlib 
Checking for g++                         : ok  
Checking for program gcc or cc           : /usr/bin/gcc 
Checking for program ar                  : /usr/bin/ar 
Checking for program ranlib              : /usr/bin/ranlib 

....
 Checking for header ['sys/types.h', 'sys/event.h'] : not found 
Checking for header sys/queue.h                    : yes 
Checking for function kqueue                       : not found 
Checking for header sys/select.h                   : yes 
Checking for function select                       : yes 
Checking for header sys/eventfd.h                  : yes 
Checking for function eventfd                      : yes 
Checking for SYS_clock_gettime                     : yes 
Checking for library rt                            : yes 
Checking for function clock_gettime                : yes 
Checking for function nanosleep                    : yes 
Checking for function ceil                         : yes 
Checking for fdatasync(2) with c++                 : yes 
'configure' finished successfully (2.194s)



컴파일을 하고, 설치를 완료한다. 

$ make
$ sudo make install



정상적으로 설치 되었는지 확인한다.  node.js 소스 예제(example)을 하나 만든다. 
hello를 표준 출력으로 나오게 하고, 2초 뒤에 world 를 출력한다.  


$ gedit helloworld.js

var sys = require("sys")
sys.puts("hello");
setTimeout(function() {
    sys.puts("world");
}, 2000);


$ node helloword.js 
hello
(2초 뒤) 
world
(종료)

$  



이번엔 tcp 서버 테스트를 진행한다.


터미널 #1
$ gedit helloworld-tcp.js

var tcp = require("net");
 
 tcp.createServer(function(c) {
     c.write("hello world!\n");
    c.end();
 }).listen(8000);


$ node helloworld-tcp.js
(서버)



터미널 #2
$ node helloworld-tcp.js
telnet localhost 8000
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello world!
Connection closed by foreign host.



http 서버를 만들어 본다.

node helloworld-http.js

var http = require("http");
     
http.createServer(function(req, res) {
    res.writeHead(200, {"Content-Type": "text/plain"});
    res.write("Hello World!!\r\n");
    res.end();
}).listen(8000);

 $ node helloworld-http.js
(서버)



브라우져로 http://localhost:8000/ 로 접속하면
Hello World!! 가 출력하는 것을 볼 수 있다.


 





마지막으로 시스템 명령어도 내릴 수 있다.


$ gedit system.js

var sys = require("sys"),

spawn = require("child_process").spawn;
 
var ls = spawn("ls", ["-hls", "/"]);
ls.stdout.addListener("data", function(data) {
    sys.print(data);
});


ls -hls  / 의 결과가 출력된다.

$ node system.js 
합계 104K
4.0K drwxr-xr-x   2 root   root   4.0K 2011-10-11 10:30 bin
4.0K drwxr-xr-x   3 root   root   4.0K 2011-10-11 10:31 boot
4.0K drwxr-xr-x   3 root   root   4.0K 2011-10-13 11:35 build
4.0K drwxr-xr-x   2 root   root   4.0K 2011-10-11 10:04 cdrom
4.0K drwxrwxrwx   2 cubrid cubrid 4.0K 2011-10-13 10:35 cubridmanager
   0 drwxr-xr-x  17 root   root   3.6K 2011-10-27 19:17 dev
 12K drwxr-xr-x 138 root   root    12K 2011-10-28 18:20 etc
4.0K drwxr-xr-x   4 root   root   4.0K 2011-10-25 11:05 home
   0 lrwxrwxrwx   1 root   root     33 2011-10-11 10:31 initrd.img -> boot/initrd.img-2.6.32-34-generic
   0 lrwxrwxrwx   1 root   root     33 2011-10-11 10:06 initrd.img.old -> boot/initrd.img-2.6.32-28-generic
 12K drwxr-xr-x  20 root   root    12K 2011-10-11 10:30 lib
 16K drwx------   2 root   root    16K 2011-10-11 10:01 lost+found
4.0K drwxr-xr-x   4 root   root   4.0K 2011-10-27 10:08 media
4.0K drwxr-xr-x   2 root   root   4.0K 2010-04-23 19:11 mnt
4.0K drwxr-xr-x   5 root   root   4.0K 2011-10-13 10:35 opt
   0 dr-xr-xr-x 182 root   root      0 2011-10-27 10:07 proc
4.0K drwx------  12 root   root   4.0K 2011-10-28 18:48 root
4.0K drwxr-xr-x   2 root   root   4.0K 2011-10-11 10:37 sbin
4.0K drwxr-xr-x   2 root   root   4.0K 2009-12-06 06:55 selinux
4.0K drwxr-xr-x   2 root   root   4.0K 2011-02-11 22:04 srv
   0 drwxr-xr-x  12 root   root      0 2011-10-27 10:07 sys
4.0K drwxrwxrwt  15 root   root   4.0K 2011-10-28 19:04 tmp
4.0K drwxr-xr-x  11 root   root   4.0K 2011-10-11 15:05 usr
4.0K drwxr-xr-x  16 root   root   4.0K 2011-10-11 12:05 var
   0 lrwxrwxrwx   1 root   root     30 2011-10-11 10:31 vmlinuz -> boot/vmlinuz-2.6.32-34-generic
   0 lrwxrwxrwx   1 root   root     30 2011-10-11 10:06 vmlinuz.old -> boot/vmlinuz-2.6.32-28-generic




websocket을 테스트해본다.


서버 코드
간단하게 테스트할려고. socket.io를 설치 없이 node.js 단에서 한 테스트.. 


websocket.js

var sys = require('sys'), ws = require('./ws');

ws.createServer(function (socket) {
socket.addListener("connect", function (resource) {
      sys.debug("connect: " + resource);
//socket.write("welcome WebSocket Server\r\n");
setTimeout(socket.end, 100 * 1000); 

}).addListener("data", function (data) {
console.info("read data: " + data);
//socket.write(data);

}).addListener("close", function () {
sys.puts("client left");
})

}).listen(8000);


 
ws.js  (https://github.com/ncr/node.ws.js 에서 조금 수정한 버전) 
이 내용을 잘 살피면서 websocket handshake에 대한 감을 잡을 수 있었음..

 // Github: http://github.com/ncr/node.ws.js
// Compatible with node v0.1.91
// Author: Jacek Becela
// Contributors:
//   Michael Stillwell  http://github.com/ithinkihaveacat
//   Nick Chapman       http://github.com/nchapman
//   Dmitriy Shalashov  http://github.com/skaurus
//   Johan Dahlberg
//   Andreas Kompanez
//   Samuel Cyprian http://github.com/samcyp
// License: MIT
// Based on: http://github.com/Guille/node.websocket.js

function nano(template, data) {
  return template.replace(/\{([\w\.]*)}/g, function (str, key) {
    var keys = key.split("."), value = data[keys.shift()];
    keys.forEach(function (key) { value = value[key];});
    return value;
  });
}

function pack(num) {
  var result = '';
  result += String.fromCharCode(num >> 24 & 0xFF);
  result += String.fromCharCode(num >> 16 & 0xFF);
  result += String.fromCharCode(num >> 8 & 0xFF);
  result += String.fromCharCode(num & 0xFF);
  return result;
}

var sys  = require("sys"),
  net    = require("net"),
  crypto = require("crypto"),
  requiredHeaders = {
    'get': /^GET (\/[^\s]*)/,
    'upgrade': /^websocket$/,
    'connection': /^Upgrade$/,
    'host': /^(.+)$/,
    'origin': /^(.+)$/
  },
  handshakeTemplate75 = [
    'HTTP/1.1 101 Web Socket Protocol Handshake', 
    'Upgrade: websocket', 
    'Connection: Upgrade',
    'WebSocket-Origin: {origin}',
    'WebSocket-Location: {protocol}://{host}{resource}',
    '',
    ''
  ].join("\r\n"),
  handshakeTemplate76 = [
    'HTTP/1.1 101 WebSocket Protocol Handshake', // note a diff here
    'Upgrade: websocket',
    'Connection: Upgrade',
    'Sec-WebSocket-Origin: {origin}',
    'Sec-WebSocket-Location: {protocol}://{host}{resource}',
    '',
    '{data}'
  ].join("\r\n"),
  flashPolicy = '<cross-domain-policy><allow-access-from domain="*" to-ports="*" /></cross-domain-policy>';



exports.createSecureServer = function (websocketListener, credentials, options) {
if (!options) options = {};
options.secure = credentials;
return this.createServer(websocketListener, options);
};

exports.createServer = function (websocketListener, options) {
  if (!options) options = {};
  if (!options.flashPolicy) options.flashPolicy = flashPolicy;
  // The value should be a crypto credentials
  if (!options.secure) options.secure = null;

  return net.createServer(function (socket) {
//Secure WebSockets
var wsProtocol = 'ws';
if(options.secure) {
 wsProtocol = 'wss';
 socket.setSecure(options.secure);
}

console.info("1");

    socket.setTimeout(0);
    socket.setNoDelay(true);
    socket.setKeepAlive(true, 0);

console.info("2");

    var emitter = new process.EventEmitter(),
      handshaked = false,
      buffer = "";
      
console.info("3");
    function handle(data) {
      buffer += data;
      
console.info("4");
      var chunks = buffer.split("\ufffd"),
        count = chunks.length - 1; // last is "" or a partial packet
        
console.info("5");
      for(var i = 0; i < count; i++) {
        var chunk = chunks[i];
        if(chunk[0] == "\u0000") {
console.info("6");
          emitter.emit("data", chunk.slice(1));
        } else {
console.info("7");
          socket.end();
          return;
        }
      }
      

      buffer = chunks[count];
console.info("6");
    }

    function handshake(data) {
console.info("handshake");
      var _headers = data.split("\r\n");

      if ( /<policy-file-request.*>/.exec(_headers[0]) ) {
        socket.write( options.flashPolicy );
        socket.end();
console.info("handshake-1");
        return;
      }

      // go to more convenient hash form
      var headers = {}, upgradeHead, len = _headers.length;
      if ( _headers[0].match(/^GET /) ) {
        headers["get"] = _headers[0];
      } else {
console.info("handshake-2");
        socket.end();
        return;
      }

console.info("handshake-3");
      if ( _headers[ _headers.length - 1 ] ) {
        upgradeHead = _headers[ _headers.length - 1 ];
        len--;
      }
      while (--len) { // _headers[0] will be skipped
        var header = _headers[len];
        if (!header) continue;

        var split = header.split(": ", 2); // second parameter actually seems to not work in node
        headers[ split[0].toLowerCase() ] = split[1];
      }
console.info("handshake-4");

      // check if we have all needed headers and fetch data from them
      var data = {}, match;
      for (var header in requiredHeaders) {



        //           regexp                          actual header value
// modified
console.info("handshake-5 header param - [" + header + "] : " + headers[header] );

        if ( match = requiredHeaders[ header ].exec( headers[header] ) ) {
          data[header] = match;
        } else {
console.info("handshake-5 end.. requiredHeader");
          socket.end();
          return;
        }
      }

console.info("handshake-6");

      // draft auto-sensing
      if ( headers["sec-websocket-key1"] && headers["sec-websocket-key2"] && upgradeHead ) { // 76
console.info("handshake-7");
        var strkey1 = headers["sec-websocket-key1"]
          , strkey2 = headers["sec-websocket-key2"]

          , numkey1 = parseInt(strkey1.replace(/[^\d]/g, ""), 10)
          , numkey2 = parseInt(strkey2.replace(/[^\d]/g, ""), 10)

          , spaces1 = strkey1.replace(/[^\ ]/g, "").length
          , spaces2 = strkey2.replace(/[^\ ]/g, "").length;

        if (spaces1 == 0 || spaces2 == 0 || numkey1 % spaces1 != 0 || numkey2 % spaces2 != 0) {
console.info("handshake-7 end");
          socket.end();
          return;
        }

        var hash = crypto.createHash("md5")
        , key1 = pack(parseInt(numkey1/spaces1))
        , key2 = pack(parseInt(numkey2/spaces2));
        
        hash.update(key1);
        hash.update(key2);
        hash.update(upgradeHead);

        socket.write(nano(handshakeTemplate76, {
          protocol: wsProtocol,
// modified
          resource: data.get[1],
          host:     data.host[1],
          origin:   data.origin[1],
          data:     hash.digest("binary")
        }), "binary");

      } else { // 75
console.info("handshake-8");
        socket.write(nano(handshakeTemplate75, {
          protocol: wsProtocol,
//modified
          resource: data.get[1],
          host:     data.host[1],
          origin:   data.origin[1]
        }));

      }

      handshaked = true;
      emitter.emit("connect", data.get[1]);
console.info("handshake-9");
    }

    socket.addListener("data", function (data) {
      if(handshaked) {
        handle(data.toString("utf8"));
      } else {
        handshake(data.toString("binary")); // because of draft76 handshakes
                }
    }).addListener("end", function () {
console.info("handshake-9 end..");
      socket.end();
    }).addListener("close", function () {
      if (handshaked) { // don't emit close from policy-requests
        emitter.emit("close");
      }
    }).addListener("error", function (exception) {
      if (emitter.listeners("error").length > 0) {
        emitter.emit("error", exception);
      } else {
console.info("exception");
        throw exception;
                }
    });


   console.info("9");
    emitter.remoteAddress = socket.remoteAddress;
    
    emitter.write = function (data) {
      try {
        socket.write('\u00', 'binary');
        socket.write(data, 'utf8');
        socket.write('\uff', 'binary');
      } catch(e) { 
   console.info("socket error -9");
        // Socket not open for writing, 
        // should get "close" event just before.
        socket.end();
      }
    };
    
   console.info("10");
    emitter.end = function () {
 console.info("emitter.end");
      socket.end();
    };
    
    websocketListener(emitter); // emits: "connect", "data", "close", provides: write(data), end()
  });
};





8000번 포트로 접속하고  아래 http 명령어를 날려봄

 GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com:8080
Origin: http://www.example.com 

정상적으로 잘 나온다. 

$ telnet localhost 8000
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com:8080
Origin: http://www.example.comHTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: websocket
Connection: Upgrade
WebSocket-Origin: undefined
WebSocket-Location: ws://example.com:8080/

(커넥션 연결된 상태)




클라이언트 (브라주져. ws.html) 코드


<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">

function WebSocketTest() {

  if ("WebSocket" in window) {

     alert("WebSocket is supported by your Browser!");
     
     var socket = new WebSocket("ws://localhost:8000");

     socket.onopen = function() {
        //ws.send("hello world");
        alert("Message is sent...");
            };



     socket.onmessage = function (evt) { 
        var received_msg = evt.data;
        alert("Message is received..." + received_msg);
            };

socket.onerror = function (error) {
  alert("error.." + error);
};


     socket.onclose = function() { 
        alert("Connection is closed..."); 
           };



 } else {
     alert("WebSocket NOT supported by your Browser!");
   }
}


</script>
</head>
<body>
<div id="sse">
   <a href="javascript:WebSocketTest()">Run WebSocket1</a>
</div>

</body>
</html>



내가 가지고 있는 크롬 웹 브라우져에서는 connection을 맺자마자 바로 fin 패킷을 보내면서 connection을 종료한다. 어딘가 약간 잘못된 것 같기는 하지만, 데모용으로만 쓸 거라서, 문제 원인을 자세히 파악하는 것은 패쓰.. 맛만 봤다는 점에서 통과해야겠음.

와이어샤크 정보





다음에는 websocket 원리를 봐야지..








<부록>

node.js를 사용한 이유는 머 간단하 websocket 테스트하려고 한것 이었는데. 쓰면서 문제점들이 좀 발견되었다. 

* node.js 의 문제점 

#1. 버그 하나로 시스템에 영향을 줄 수 있음

아래 코드에서 response 객체에 대한 end() function이 호출되지 않았을 때, 치명적으로 문제가 생긴다.
하나의 요청에서 end가 안되었기 때문에 모든 요청은 blocking된 요청이 끝나기를 기다려야 한다. 
버그 하나에 치명적임..

var http = require("http");
     
http.createServer(function(req, res) {
    res.writeHead(200, {"Content-Type": "text/plain"});
    res.write("Hello World\r\n");

    //res.end();
}).listen(8000);




#2 피보나치 이슈 (node.js에 재귀적 메소드에 문제가 있는 것 같다. )

 
재귀적 함수(피보나치)에 대해서 속도 이슈가 있다. 

var http = require("http");

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end(fibonacci(30).toString());
}).listen(8000);

function fibonacci(n) {
  if (n < 2)
    return 1;
  else
    return fibonacci(n-2) + fibonacci(n-1);
}



결과값은 아래과 같이 확인한다. 

$ time curl http://localhost:8000



10에 대한 피보나치 수열의 값을 구했을때는 0.007초가 걸린다. 
  res.end(fibonacci(10).toString());

$ time curl http://localhost:8000
10946
real 0m0.007s
user 0m0.000s
sys 0m0.004s




30에 대한 피보나치 수열의 값을 구했을때는 0.053초가 걸린다. 
  res.end(fibonacci(30).toString());

 $ time curl http://localhost:8000
1346269
real 0m0.053s
user 0m0.004s
sys 0m0.000s



아래와 같이 40의 피보나치 수열의 값을 구했을때는 4초 이상이 걸린다. 

  res.end(fibonacci(40).toString());
 

$ time curl http://localhost:8000
165580141
real 0m4.312s
user 0m0.008s
sys 0m0.000s



100의 피보나치 수열의 값을 구할때는 상상을 초월한다. 

  res.end(fibonacci(100).toString());
 

$ time curl http://localhost:8000

30분동안 아무런 응답이 없어서, 그냥 종료시켰다. 



cpu는 최대한 활용하고 있다. 엔진의 이슈일까?? 



 #3. 코드 관리
자바스크립트 특성상, 코드 관리를 잘 해야 한다. BO가 들어가는 순간부터 복잡해질 것 같다. ...
















'scribbling' 카테고리의 다른 글

websocket #4 (웹소켓의 한계)  (1) 2011.11.02
websocket #3  (0) 2011.10.31
websocket #1  (0) 2011.10.28
Comet에 대한 일반론  (0) 2011.10.28
글쓰기 전략  (0) 2011.10.27
Posted by '김용환'
,

websocket #1

scribbling 2011. 10. 28. 18:40

이미 long polling이 대세인 상태에서, WebSocket이 앞으로 대세가 될지는 모르겠다.
수많은 웹 게임은 short polling 으로, 일부 웹 게임 또는 웹채팅은 long polling으로, flashsocket을 이용한 streaming 방식을 websocket이 대체하기는 많은 시간이 흘러야 하지 않을까?

websocket을 브라우져에서 지원하는 현황(http://caniuse.com/#search=socket)을 보더라도 당장 쓰기가 쉽지 않다. 


  
그렇다하다도, 미리 공부해도 준비하는 것도 나쁘지 않다. tcp도 보편화될때까지 많은 시간이 걸리지 않았는가? 새롭고 좋은 것들은 계속 나와도 무방하다. ㅎ

하여튼, 이런 복잡한 대안안에서 프레임워크 형태인  socket.io를 찾는 것 같다.
socket.io는 node.js의 하나의 모듈로서, websocket 뿐 아니라, flashsocket, long polling, streaming, jsonp polling을 잘 추상화하였다.

http://socket.io/ 홈페이지에 있듯이, 서버는 단순하게 80포트를 열고 socket.io만 읽으면 되며, 클라이언트는 간단하게 접속하면 되는 스크립트 프레임워크이다. 


서버 
 var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});


클라이언트
<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script> 


이 녀석은 Internet Explorer 5.5+, Safari 3+, Google Chrome 4+, Firefox 3+, Opera 10.61+,
iPhone Safari, iPad Safari, Android WebKit, WebOs WebKit 등을 지원하기 때문에
아주 현실적인 대안이 된다.

실제로도 서비스에서 많이 사용하고 있다.



인제 차근 차근 websocket에 대해서 공부해봐야지. 이제 시작..
 

'scribbling' 카테고리의 다른 글

websocket #3  (0) 2011.10.31
websocket #2 (node.js 설치)  (1) 2011.10.31
Comet에 대한 일반론  (0) 2011.10.28
글쓰기 전략  (0) 2011.10.27
요즘 Nosql 트렌드 (2011년 10)  (0) 2011.10.20
Posted by '김용환'
,

작년에 Comet에 대해서 작성했던 글을 공유.

'scribbling' 카테고리의 다른 글

websocket #2 (node.js 설치)  (1) 2011.10.31
websocket #1  (0) 2011.10.28
글쓰기 전략  (0) 2011.10.27
요즘 Nosql 트렌드 (2011년 10)  (0) 2011.10.20
가트너에서 발표한 2012년 top10 IT 기술 동향  (0) 2011.10.20
Posted by '김용환'
,

글쓰기 전략

scribbling 2011. 10. 27. 11:47

글을 쓸 때마다 너무 고통스럽다. 내가 생각하는 것을 글로 표현하는 것은 참 어렵다. 공부해야 한다...


POWER 전략

1. prewriting

브레인스토밍, 주제와 대상독자, 목적과 방향과 아이디어를 수집, 일정 수립, 독자 분석


 

   - 독자의 학력, 용어 이해 수준에 따라서 용어 선택은 달라져야 한다.  -> 글의 수준과 방향이 결정

   - 주제에 대한 사전정보 및 선행지식은 무엇인가?

   => why? 상대방이 알고 싶어하는 정보가 무엇인가? 전달능력 확보.

 

2. organization

문서 구조를 잡음, 마인드 맵 이용

생각을 정리함. 순차적 접근시 독자의 이해가 가장 빠르다.

목차를 잡는다.

 (1) 개요, 정의, 환경 (2) 절차 (task), 기능

하위 문서 구조로 많이 들어가지 않게 한다. 2단계정도로.. 많으면 3단계

  1.

  1.1

  1.1.1                            



 
3. writing -
시각자료와 함께 글 내용 작성 (정확성, 간결성, 통일성, 평이성, 형식성), 읽은 것은 10%를 기억하지만, 본 것은 30%를 기억한다.

처음부터 시각 자료를 활용하는 것을 계획한다.

시각 자료를 언제 활용할지 결정하는 요소 - 제한된 공간에 많은 데이터를 제시할 때, 비교, 정확히. 쉽게 사용하기

시각 자료 - 테이블,

볼드체를 이용, 간결하게, 주제를 항상 먼저 쓰고, 부연설명은 그 뒤에 적는다.

정의를 잘해야 한다. 객관적이고, 구체적이고 명확해야 한다.

순차적인 설명할 때는 번호(1, 2, 3)을 주어 짧게 주요 내용만을 적어서 간결하게 한다.

외래어 표기, 한글 맞춤법 확인 :    http://urimal.cs.pusan.ac.kr/urimal_new/

첫화면 > 자료실 > 연구보고서 > 기타 공개 자료 (http://korean.go.kr/09_new/data/etc_view.jsp)



4. editing - 문서 구조, 문법, 맞춤법 수정

검토리스트 작성 (작성 범위, 용어 및 내용의 일관성, 단락 배열, 연결어 사용, 수동태/번역식 표현, 중복 표현, 출처, 띄어쓰기, 맞춤법, 애매하게 안쓰기)

글을 쓰고 나서, 24시간 이후에 검토해서 다시 수정



5. rewriting -
검토 (동료나 전문가)   

 




 

Posted by '김용환'
,