카테고리 없음

웹소켓 과 SSE(Server-Sent-Event) 차이점 알아보고 사용해보기

志者必得 2021. 5. 10. 10:54

최근에 어떤 이벤트가 생겼을 때 client side에 ui를 업데이트해야 되는 기능을 구현해야 됐었습니다. 처음에는 이런 경우에 사용할 수 있는 것이 socket 밖에 몰라서  socket.io를 사용해서 socket으로 만들다가 웹소켓을 공부하다가 보니 SSE(Server-Sent-Event)라는 것을 알게 되었습니다. 제가 평소에 공부를 해두었다면 웹소켓으로 안 만들고 SSE를 사용해서 만들었을 텐데 시간 낭비를 해버렸습니다. 이래서 평소에 공부를 해야 되는 것 같습니다. Socket과 SSE에 가장 큰 차이점을 하나 말해보라고 한다면 Socket은 양방향으로 데이터를 주고받을 수 있지만 SSE(Server-Sent-Event)를 사용하게 되면 클라이언트는 데이터를 받을 수만 있게 됩니다. 그러니까 어떤 기능이 필요한지에 따라서 뭐를 사용할지 결정하면 됩니다. 

 

 

웹소켓과 SSE(Server-Sent-Event)에 차이점

 

Socket과 SSE에 가장 큰 차이점을 하나 말해보라고 한다면 Socket은 양방향(bidirectional)으로 데이터를 주고 받을 수 있지만 SSE(Server-Sent-Event)를 사용하게 되면 클라이언트는 데이터를 받을 수만(mono-directional) 있게 됩니다. 그러니까 어떤 기능이 필요한지에 따라서 뭐를 사용할지 결정하면 됩니다. 

 

  Socket Server-Sent-Event
브라우저 지원 대부분 브라우저에서 지원  대부분 모던 브라우저 지원(polyfills 가능)
통신 방향 양방향 일방향(서버에서 클라이언트로)
리얼타임 Yes Yes
데이터 형태 Binary, UTF-8 UTF-8
자동 재접속 No Yes(3초마다 제시도)
최대 동시 접속 수 브라우저 연결 한도는 없지만 서버 셋업에 따라 다름  HTTP를 통해서 할 때는 브라우저당 6개 까지 가능 / HTTP2로는 100개가 기본
프로토콜 websocket HTTP
베터리 소모량 작음
Firewall 친화적 Nope Yes

 

차이점 부연 설명 

 

브라우저 지원

 

웹소켓은 IE 10부터 지원하고 전세계 유저에 98.16%가 네이티브 하게 사용 가능

Server-sent events는 IE는 지원을 안 하고 전 세계 유저에 97%가 사용 가능함

서버 사이드 이벤트 지원 브라우저

브라우저가 SSE를 지원하는지 안 하는지 알아보는 방법 자바스크립트

if ('EventSource' in window) {
  // use polyfills
}
var source = new EventSource('URL');

 

최대 동시 접속 수

 

Websocket

 

웹소켓은 서버에 셋업에 따라 얼마나 많이 접속할 수 있는지 정해지기 때문에 딱 정해진 숫자는 없다. 

아래 스택오버플로우를 봐도 어떤 사람은 300k 동접을 가능하게 했다고 하고 어떤 사람은 다르다.

stackoverflow.com/questions/15872788/maximum-concurrent-socket-io-connections

(위에 나오는 서버 셋업은 함부로 따라 하지 말자)

 

SSE

 

아래는 HTTP2를 사용하지 않을 경우에는 브라우저에서 6 정도로 제한하고 있다. 텝을 6개 이상 열리면 안 될 수 있다. 그리고 앞으로도 크롬에나 파이어폭스에서는 고치지 않을 것이라고 한다. 하지만 HTTP2를 사용하면 기본으로 100개를 허용한다.

더보기

When not used over HTTP/2, SSE suffers from a limitation to the maximum number of open connections, which can be especially painful when opening multiple tabs, as the limit is per browser and is set to a very low number (6). The issue has been marked as "Won't fix" in Chrome and Firefox. This limit is per browser + domain, which means that you can open 6 SSE connections across all of the tabs to www.example1.com and another 6 SSE connections to www.example2.com (per Stackoverflow). When using HTTP/2, the maximum number of simultaneous HTTP streams is negotiated between the server and the client (defaults to 100). - 출처 모질라

배터리 및 데이터 사용량

 

네트워크 텝 열어서 보면 알겠지만 소켓은 계속 서버랑 계속 handshake를 하고 있습니다. 하지만 SSE는 한번 열어두고 계속 기다리고 있습니다. 아무리 소켓이 서버에 보내는 데이터가 적긴 하지만 계속 열려 있다면 어쩼든 왔다 갔다 하니까 더 클 수밖에 없습니다.

 

 

소켓과 SSE 사용처

 

위에서 보는 것처럼 websocket과 SSE에 차이점 때분에 사용되는 곳이 조금 다를 수 있다. 웹소켓은 주로 리얼타임이 필요한 곳에서 많이 사용된다. 

 

카카오톡 쳇(SSE와 HTTP로도 만들 수는 있음)

주식 트레이딩 데이터

크립토 실시간 차트 등이 있다.

 

SSE는 많이 사용되는 곳이 알람을 줄 때 많이 사용된다. 예를 들어 Twitter에서 피드를 받을 때 또는 페북에서 친추 요청을 받았을 대 등등. 왜냐하면 클라이언트에서는 데이터를 받기만 하면 되고 완전히 실시간일 필요는 없기 때문이다.

 

SSE 사용해보기

 

server.js(node express)

 

SSE를 사용하기 위해서 서버에서 해야 될 일은 그렇게 많지 않고 해더를 아래와 같이 보내야 합니다.

 

Content-Type: 브라우저에게 우리가 text 형태의 이벤트 스트림을 보낼 꺼다라고 말해주는 부분

Connection: 브라우저에게 커낵션을 닫지 말고 계속 열어두고 기다리고 있어라

계속 새로운 데이터가 올 것이기 때문에 캐시는 필요 없음으로 no-Cache

// 먼저 해더를 아래와 같이 보내야 합니다.
const headers = {
    'Content-Type': 'text/event-stream',
    'Connection': 'keep-alive',
    'Cache-Control': 'no-cache',
}

위에서 보는 것처럼 이게 거의 다입니다.

res.writeHead(200, headers)
 
const clientId = request.query.clientId
clients[clientId] =  {
  response,
}
request.on('close', () => {
  delete clients[clientId]
})
// 이제 서버에서 어떤 이벤트가 발생 했을 때 데이터 클라이언트로 보내기

// 예시 서버 최초 9+ 강화 성공
const notifyUser = (req, res) => {
  const payload = {...}
  clients.forEach(client =>
  	client.response.write(`data: ${JSON.stringify(payload)}\n\n`)
}

눈여겨봐야 할 점은 데이터를 보낼 때 맨 끝에 \n\n을 써줘야 하는 것입니다. \n\n이 이벤트 스트림에 끝이라고 알려주는 방법입니다.

 

 

버퍼 없애기(버퍼가 있으면 클라이언트에게 바로 안 보내고 잠시 기다림)

 

HTTP header - X-Accel-Buffering: no

ngnix config - proxy_buffering off

 

노드로는 10000 커넥션까지 가능

 

클라이언트 사이드

useEffect(() => {
  // 너와 나의 연결고리 만들어 주기
  const sseEvents = new EventSource('http://localhost:3000/sse')


  sseEvents.onopen = function() {
    // 연결 됐을 때 
  }
  sseEvents.onerror = function (error) {
    // 에러 났을 때
  }
  sseEvents.onmessage = function (stream) {
    // 메세지 받았을 때
    const parsedData = JSON.parse(stream.data)
  }
}, [])

이렇게 클라이언트에서 EventSource로 연결을 하게 되면 네트워크 텝에서 아래와 같이 보이게 됩니다.

 

마지막으로 총 청리

 

웹소켓과 SSE에 가장 큰 차이점은 통신 방향이다. 웹소켓은 양방향 SSE는 단방향이기 때문에 클라이언트가 데이터를 보낼 필요가 있을 때는 소켓. 예를 들어 FPS 게임 같은 경우. 하지만 SSE는 서버에서 클라이언트로만 데이터 전송이 가능하기 때문에 주로 노티를 줄 때 많이 사용된다. 지원하는 브라우저 같은 경우 IE를 빼고 생각한다면 둘 다 거의 대부분에 모던 브라우저에서 Polyfills 없이 사용이 가능하다. 하지만  Server-Sent Event도 Polyfills를 사용하면 되기 때문에 큰 문제가 되진 않는다. SSE를 사용할 때 buffer만 꺼주면 소켓이랑 같이 실시간 업데이트가 가능하다. SSE를 사용할 때 주의할 점은 HTTP/1을 사용할 경우 브라우저에 최대 연결 수가 보통 6개로 제한되기 때문에 6개 이상 텝을 열었을 때 작동이 잘 안 될 수가 있다. 하지만 HTTP/2를 사용할 경우 기본 최대 연결 수가 100이 됨으로 문제가 될 가능성이 많이 줄어든다. 소켓은 서버와 연결이 끈겼을 때 자동으로 연결해주는 기능이 없기 때문에 스스로 코드를 짜야되지만 서버사이드 이벤트 같은 경우에는 자동으로 3초마다 한 번씩 확인을 한다. 서버사이드 이벤트 같은 경우에는 firewall이 있는 경우도 사용이 큰 문제없이 가능하기 때문에 firewall이 있을 경우 사용을 고려하는 것도 좋다.

 

 

이상으로 웹소켓과 서버 사이드 이벤트에 차이점과 구현하는 법과 사용법을 알아보았습니다. 질문이 있거나 개선할 점이 있다면 댓글로 남겨주세요.

2023.01.04 - [분류 전체보기] - 계발자를 위한 vscode extensions 추천 리스트 2023

2022.09.19 - [분류 전체보기] - 개인 프로젝트 타이머를 만들면서 배운 점 및 해결한 문제들