0.7에 대한 발표글을 보면 기능개선에 대해서 여러가지를 설명해주고 있는데 웹소켓이 기본적으로 가진 문제점에 대해서 얘기하고 있습니다. 웹소켓은 웹브라우저가 웹소켓을 초기화 했을때 하나의 소켓만이 단 하나의 프로토콜이나 목적을 위해서 데이터를 스트림할 수 있습니다. 그래서 다음과 같은 문제가 발생합니다.
- 메시지를 어떻게 인코딩하고 인터프리팅해야 하는지 생각해야 합니다.
- 서드파티 모듈들과 상호작용을 하기가 어렵습니다.
- 애플리케이션의 "연결", "연결해지"에 대한 로직이 존재하지 않습니다.
- 기능적으로 서브셋에 대한 인증이나 오류처리는 더더욱 어렵습니다.
이러한 문제를 해결하기 위해서 Socket.iO에서는 여러가지 기능이 추가되었는데 대표적인 기능들은 아래와 같습니다.
네임스페이스
// 기본적인 연결
io.sockets.on('connection', function(socket) {});
// 네임스페이스 사용
var channel = io.of('/channel').on('connection', function(socket) {});
위 코드는 기본적인 연결과 네임스페이스를 사용한 것을 비교한 것입니다. 기존에 웹소켓을 사용하면 하나의 소켓네에서 데이터의 내용을 파싱해서 종류를 구분해 주어야 했다면 Socket.IO에서는 네임스페이스를 이용해서 용도별로 구분해 줄 수 있습니다.
커스텀 이벤트
이전에는 message 이벤트를 통해서 서버와의 JSON데이터를 주고 받았었지만 이제는 추가적으로 커스텀이벤트를 사용할 수 있습니다.
// message 이벤트
socket.on('message', function(msg) {
socket.send(msg);
});
// 커스텀 이벤트
socket.on('anything as you like', function(msg) {
socket.emit('anything as you like', msg);
});
semd() 메서드는 기존처럼 message 이벤트를 사용하지만 emit()을 사용해서 첫번째 파라미터에 이벤트명을 원하는대로 주고 클라이언트와 데이터를 주고 받을 수 있게 되었습니다.
Room 기능
socket.join('the room');
socket.broadcast.to('the room').send('something to say');
기존에는 Socket을 연결한 본인과 데이터를 주고 받거나 브로드캐스팅을 통해서 그외 모두하고만 통신할 수 있었습니다만 이제는 Room기능이 추가되어서 socket내에서나 네임스페이스 내에서 임의로 지정한 Room이름에 조인을 해서 같은 방에 있는 사람하고만 데이터를 주고 받을수 있게 되었습니다.
이 외에도 여러가지 기능들이 추가가 되었습니다. 처음 0.7이 발표가 되고 새로 추가된 기능이 꽤 괜찮아 보여서 JCO에서 만들었던 리얼타임앱을 Socket.IO용으로 포팅하려고 했었는데 기능들의 사용법이 익숙하지 않아서 기능을 익힐겸 예제를 만들기 시작했습니다. 사실 초반에는 문서도 잘못된 부분도 꽤 있었고 네임스페이스관련해서 기능이 제대로 동작하지 않은 버그들이 꽤 많았기 때문에 Github에 리포팅하고 수정되기를 기다리다 보니 거진 한달이 다 되어버렸습니다. 그래도 0.7.7에서는 대부분의 이슈들이 해결되어서 작성하던 예제를 완성했습니다.
위 페이지에 관련된 소스를 적어놨으므로 이런저런 설명보다는 소스랑 동작을 집접 보는게 이해하기가 편하리라 생각해서 설명에 대한 것은 간략히만 하고 넘어갑니다. 위 예제의 소스는 Github에 올려져 있으며 Socket.IO의 공식페이지의 디자인을 그대로 가져와서 페이지를 구성했는데 이 디자인을 가져온 것은 Socket.IO를 만드는 Guillermo Rauch로부터 허락을 받아서 사용한 것입니다. (그냥 기능을 테스트하기 위해서 만든 예제페이지이므로 XSS같은 시도는 하지 말아주세요 ㅠㅠ)
0.7 발표 공지에 새로운 기능들에 대해서 간략히 설명되어 있으며 자세한 사용법에 대해서는 How to Use에 나와있으며 기존의 0.6사용자를 위한 Migration Guide도 참고할 만합니다.
good job!!
Thanks
질문이 몇 가지 있습니다.
제가 우선 만들고 싶은 것은 두 모바일 기기 간의 채팅 프로그램입니다.
지식인도 아닌데 질문하게 되어 죄송합니다.
첫 째는 모바일 기기(iPhone 혹은 iPad)의 슬립모드와 관련된 것입니다. 슬립모드에서는 클라이언트가 서버에서 보내오는 메세지를 받을 수가 없는데, 이 때 서버가 클라이언트의 disconnection을 알 수 있는지 여부입니다. disconnect라고 판정하는 시점도 애매하고 서버 측 disconnect이벤트는 발생하지 않는 거 같아서요.
두 번째는 메세지를 .volatile로 보내면 그냥 메세지가 갔는지 안갔는지 확인을 안하는 건가요? git 페이지에 영어로 되어 있어서 해석이 잘 안되서요. 제가 슬립모드가 된 아이폰에 계속 메세지를 emit하니깐 서버가 뻣어버렸는데 메세지를 보낼 때 .volatile를 붙여서 emit하니깐 서버는 안 뻣더라고여. .volatile의 정확한 사용법과 의미를 알고 싶습니다.
세 번째는 제가 슬립모드의 아이폰을 다시 켜고 사파리 브라우저의 콘솔을 확인했을 때는 websocket frame is too long에러가 뜨고 몇초 후에 웹소켓 종료에 관련된 이벤트를 확인할 수 있었는데(물론 몇초 후에 발생되었습니다) 이 때, 그 채널에 재접속을 해야 하는데 재접속은 어떻게 해야하는지 궁금합니다. http://readthedocs.org/docs/tornadio2/en/latest/bugs/#connect-after-disconnect보면은 재접속에 버그가 있고
var conn = io.connect(addr);
conn.on('disconnect', function(msg) { conn.socket.reconnect(); }); 식으로 재접속하게 되면 make sure you’re not setting up events again.라고 써있는데 이벤트를 재정의하지 말라는 소리 인가여? 재접속 기능을 구현해 보셨으면 조언이나 코드조각 좀 부탁드립니다.
저는 프로그래머는 아니고 학생이다 보니 이거 저거 막히는게 많아서 두서 없이 질문하게 되었습니다. 꼭 답변 부탁드립니다.
일단 저도 세부케이스별로 다 테스트해 본것은 아니기 때문에 디테일한 테스트를 해보기 전에는 정확한 답변을 드리지는 못할듯 합니다. 몇가지 추측은 해볼 수 있는데요.
1. 슬립모드는 사용자가 브라우저를 닫는것과는 다릅니다. 브라우저를 닫을때는 처리해줄 수 있는데 슬립모드는 그런 unload이벤트등이 발생하지 않을듯 합니다. 이건 클라이언트엣 처리할 수 없기 때문에 서버에서 타임아웃을 통해서 dicconnect가 되어야 할 것 같습니다.
https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO
heartbeats
설정에 보시면 heartbeat interval이 있습니다. 기본이 20초인데요. 클라이언트가 슬립되었으니 아마 20초동한 하트비트를 받지 못하면 서버에서 디스커넥트가 될 듯 합니다.
2. volatile은 하신 말씀이 맞습니다. socket.io는 기본적으로 전송하는 모든 메시지를 추적합니다. 네트워크나 느리거나 문제가 있어서 전송이 안되면 추적하면서 계속 전송을 하는데 volatile을 보낸뒤엔 보내고 추적하지 않습니다.
3.이 현상을 실제로 테스트해보지는 알수 없겠지만 사파리가 복귀되고 클라이언트 입장에서는 연결되었다고 생각하지만 서버에서는 끊어진 것이기 때문에 재접속을 시도하다가 실패하는 게 아닐까 생각합니다. 주신 링크는 내용상으로 봤을때는 접속이 해지된 이후 같은 채널로 접속을 하는데 버그가 있다는 이야기 같습니다. 주신 링크에 3가지 방법인데 마지막 disconnect되었을 때는 사용하는 방법은 왠만하면 쓰지 말라는 이야기 같습니다. 1이나 2번의 방법을 사용하면 될듯 합니다.
한가지 질문을 드려도 될까요? 올려주신 예제를 들여다보니.
네임스페이스와 룸의 차이점에 대해서 애매모호한 것 같습니다.
구체적으로 네임스페이스와 룸이 어떤 차이점이 있나요? 하나의 Socket.IO 모듈을 공유할 수 있다는건 알겠는데 차이점을 모르겠네요.
네임스페이스는 기능의 분리이고 룸은 메시지를 보낼 대상자를 필터링하는 기능입니다.
즉, A, B 기능이 있다면 네임스페이스가 없으면 {type: 'A'} 같은 식으로 보내서 기능을 구분해야 하지만 네임스페이스를 사용하면 URL 자체로 분리할 수 있기 때문에 메시지가 간단해 지고 코드도 구분해서 작성할 수 있습니다.
반면에 룸은 100명의 접속자중 일부에게만 베시지를 주고받고 싶을 때 룸에 포함시켜서 메시지를 전송할 수 있게 하는 기능입니다.