ㅎㅇ 웹소켓

지금 우리팀이 만들고 있는 서비스에서는, 클라이언트, 그 중에서도 admin에 대해 2가지 페이지가 돌아가고 있다. 한 화면은 테블릿에 띄울 화면이고, 다른 하나는 업장에서 확인할 웹페이지 화면인데.
(편의상 각각, tablet page, admin page라고 칭하겠다.)

서비스가 원활하게 돌아가려면, tablet 페이지에서의 변화가 admin 페이지에 인식되어, 새로운 데이터로 페이지를 리로드해야 하고. 반대로 admin페이지에서 변화가 일어나도, tablet 페이지가 리로딩되어야 했다.

그림으로 보자면 위와 같고. 만약 사용자가 늘어난다면, 하나의 서버에 많은 tablet과 admin들이 주렁주렁 달려야하는 셈이었다.
그리고! 동시에 특정 admin에서 변화가 일어나면 이와 관련된 특정 tablet에서만 실시간으로 리로드가 일어나야 했고… (vice versa)

하지만 알다시피, 변화가 일어나고, 변화를 캐치해야하는 두 페이지 모두 독립적인 클라이언트 페이지였다. 지금까지 우리가 썼던, restful API로는, 특정 클라이언트에서 서버에 요청을 하고, 그 응답받은 것을 통해 동일한 클라이언트 페이지를 업데이트 하는 방식이었는데. (혹은 서버에 요청해 데이터를 수정하던가) 위와 같은 구조를 restful API로 어떻게 구현할 수 있을까 검색하다 push와 pull 기법을 알게되었다.

pull: 클라이언트가 서버에게 먼저 요청해 데이터를 받는 방식. (흔히 썼던!)
push: 클라이언트가 매번 요청하지 않아도 사용자에게 자동으로 서버로부터 데이터를 받아오는 방식.

우리에게 필요한 방식은 , 익숙하지 않은 push방식이었다.
기본적으로 클라이언트에서 요청을 받으면 서버가 그 요청에 따른 응답을 하고 연결을 끊는, http 방식에서는, 실시간에 필요한 ‘지속적인 연결’이 불가능하고. 이를 보완하기 위해서 comet이란 방법이 존재한다는 것을 알게 되었다.

Comet

실시간 푸시를 위해서 꼭 필요한, ‘지속적인 연결’을 가능하게 하는
comet에는 polling, long-polling, streaming 등의 방식들이 있다.

1, polling: 주기적으로 클라이언트가 서버에 요청해, 고쳐진 사항이 있는지 체크하는 것. (setInterval로 서버와 주기적으로 연결하는 것과 비슷한 듯) 기본적으로, 서버와 ‘주기적’으로 통신하면서 실시간성이 떨어지고. 그렇다고 주기를 짧게 가지면, 서버가 받는 부하가 크다는 단점이 있다.

2, long-polling: 클라이언트가 연결을 해서 응답을 요청하는 Polling 형태.
+ 연결 후, 응답을 받는 것을 고의로 늦추면서, 그 안에 업데이트가 되면 클라이언트에 요청을 보내고. (http니까 요청이 끊어지겠지? 그러면) 클라이언트는 다시 서버로 요청해 업데이트를 기다리는 방식. 서버와 재연결하는 것이 연결을 유지하는 것보다 부하가 크기 때문에, 실시간 푸시가 많은 구조일수록 , 재연결이 많아지고 그러면 부하가 커진다는 단점이 있음.

3, Streaming: 클라이언트가 서버와 연결을 하면, 이후 응답완료 신호를 보내지 않고, 지속적으로 연결을 유지하는 상태. 이후 업데이트가 있으면 지속적으로 푸시를 보내는 방식. 한번 연결되면, 재연결 부하가 없지만 연결의 유효성 문제, 지원하는 브라우저가 매우 적음/ 지속적으로 보내는 청크 처리 문제? 등의 단점이 있다고 함.

4, socket: 위의 방법들의 단점을 보완하기 위해, HTML5에서 추가된 방식. 즉, 표준이기 때문에 대부분의 브라우저에서 지원이 되고. 지속적인 연결중에서도 필요한 데이터만 주고 받기 때문에 효율적. (다만, 예전 브라우저나 몇몇 브라우저는 아예 지원 안한다고 함.

우리는 웹소켓의 범용성을 넓힌 socket.io를 썼는데.
간단히는, 단방향에서 양방향성의 웹사이트를 가능케 해주는 JS 모듈이고. 이를 통해, HTTP 클라이언트로 푸쉬 메시지를 보낼 수 있다. 정도로 인지하고 있다.

socket.io는 쓰기에 매우 간단했다. 유튜브에 있는 넷닌자를 통해서 바로 쓸 수 있었는데. 간단히 말하자면, 클라이언트에서 이벤트가 일어나면 socket.io를 통해 이벤트가 일어났다고 서버에 신호를 보내고. 서버는 특정 이름의 소켓신호를 받으면, 그 안에 있는 function을 통해 다른 클라이언트에 신호를 보내주는 형식이다. 물론, 클라이언트도 마찬가지로신호를 보내는 것 말고도, 특정 이름의 신호를 받는 이벤트도 있어야 하고!

다음은 간단하게 세팅한 웹소켓이다.

서버쪽 세팅 (소켓을 열고, socket.on 을 통해 특정 이벤트를 처리한다)
클라이언트 1 세팅. (특정 서버에 소켓을 연결하고, 특정 상황에서 emit을 통해 서버에 통신을 보내고 & on을 통해 서버에서 통신을 받아 특정 이벤트를 처리한다!
클라이언트세팅. (클라이언트 1과 서로 상반되는 이름의 이벤트를 주고 받도록 세팅했다)

실시간 통신은 이렇게 생각보다 쉽게 구현해낼 수 있었다. (원리는 잘..)

그렇지만, 이 방법에도 문제가 있는데. 어느 한 클라이언트에서 소켓 통신을 보내면, 서버는 이를 받아서 모든 클라이언트에 통신을 뿌려주기 때문이다.
(그러면, 모든 클라이언트가 이 통신을 받고. 자기 아이디로 온 통신임을 확인하면, 이벤트를 키는 방식) 딱 봐도 서버에 큰 부하가 걸릴 것 같다…

그래서, 맨 위에 그린 그림처럼 서버와 특정 admin & 특정 tablet. 이렇게 3개만 묶여서 통신이 일어날 수 있도록 할 수 있을까 찾고 있다.

지금은 네임스페이스나 룸을 찾아보고 있는데. 이걸 해결하고 다시 써야겠다.

참고한 on, emit, broadcast 설명

Sending and getting data : .send or .emit.
.emit, the acknowledgement is done by you, which means you can also pass data along
imply add a broadcast flag to emit and send method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade