SSE와 WebSocket, 그들은 왜 실시간 통신 환경에서 자주 비교될까?
우리가 알림과 실시간 채팅 같은 서비스를 구현할 때, 우리는 자연스럽게 두 가지 기술 사이에서 고민한다.
`SSE`와 `WebSocket`은 각기 다른 매력을 가졌다.
실시간 통신의 필요성
앞서, 언급한 것처럼 알림을 띄우거나 실시간 채팅 서비스에서 실시간 통신은 선택이 아닌 필수이다.
그런데 문제는 단방향이냐, 양방향이냐가 된다.
양방향 통신을 택하면 더 복잡하지만 매력적이고, 단방향 통신은 기능은 적지만 그만큼 단순하다.
둘 중 어느 쪽을 고를지를 결정하기 위해서는 기술들의 성격을 좀 더 들여다 봐야 한다.
SSE (Server-Sent Events)
`SSE`는 마치 인프런 강의처럼 강사가 우리에게 일방적으로 강의를 하는 것과 같다.
청강생(클라이언트)은 계속해서 강사에게 듣고 받아 적어야 한다.
- 청강생: 강사님, 질문이 있습니다!
- SSE: 안됩니다. 질문할 수 없어요.
`SSE`는 서버가 클라이언트에게 일방적으로 데이터를 푸시할 때 사용된다.
HTTP 기반이라 프록시나 방화벽이 거부하지 않는다.
서버에서 매초마다 데이터를 보낸다고 상상해보자.
Server-Side
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
@RestController
public class SSEController {
@GetMapping("/sse")
public void streamEvents(HttpServletResponse response) throws IOException {
response.setContentType("text/event-stream");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
for (int i = 1; i <= 5; i++) {
writer.write("data: SSE 이벤트 #" + i + "\n\n");
writer.flush();
try {
Thread.sleep(1000); // 1초마다 이벤트 전송
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
writer.close();
}
}
Client-Side
const eventSource = new EventSource('/sse');
eventSource.onmessage = function(event) {
console.log("새 이벤트 수신:", event.data);
};
eventSource.onerror = function() {
console.error("SSE 연결 오류 발생");
};
장점:
- `SSE`는 자동 재연결을 지원한다.
- 설정이 간단하여 빨리 구현하고 싶은 개발자에게는 최적이다.
단점:
- 오직 단방향이다. 클라이언트는 서버에게 말을 걸 수 없다.
- 데이터를 텍스트로만 보내는게 편리하다.(이미지나 비디오 전송은 어렵다)
WebSocket
`WebSocket`은 전화를 하는 것과 똑같다.
양방향 통신이 가능하기 때문에 서버와 클라이언트가 자유롭게 대화를 주고 받는다.
- A: "지금 뭐해?"
- B: "지금 게임중"
아래는 서버와 클라이언트가 통신하는 예제이다.
Server-Side
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new TextWebSocketHandler() {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message)
throws Exception {
session.sendMessage(new TextMessage("에코: " + message.getPayload()));
}
}, "/ws");
}
}
Client-Side
const socket = new WebSocket('ws://localhost:8080/ws');
socket.onopen = () => {
console.log('WebSocket 연결 성공!');
socket.send('안녕, 서버!');
};
socket.onmessage = (event) => {
console.log('받은 메시지:', event.data);
};
장점:
- 양방향이라 서버와 클라이언트가 마음껏 대화를 할 수 있다.
- 텍스트뿐만 아니라 바이너리 데이터도 전송할 수 있다. (즉, 그림도 보내는 것이 가능하다)
단점:
- 설정이 조금 귀찮다. 방화벽에 걸리기도 쉽고, 초기 핸드쉐이크까지 해야 한다.
- 재연결? 그런건 없다. 알아서 다시 연결할 방법을 마련해야 한다.
SSE vs WebSocket
비교 항목 | SSE | WebSocket |
통신 방식 | 단방향 (서버 → 클라이언트) | 양방향 (서버 ↔ 클라이언트) |
사용 사례 | 실시간 알림, 뉴스 피드 | 채팅, 게임, 협업 도구 |
프로토콜 | HTTP/1.1 | TCP |
재연결 지원 | 자동 재연결 지원 | 별도 구현 필요 |
설정의 간편함 | 매우 간편 | 복잡함 |
방화벽 친화성 | 우호적 | 주의 필요 |
정리
SSE:
- "넌 듣기만 해, 보내는 건 나만 보낼꺼야"에 적합하다.
- 실시간 뉴스나 알림처럼 서버에서 클라이언트로만 정보가 흐를 때 좋다.
WebSocket:
- "같이 소통해요~" 스타일이다.
- 채팅, 게임처럼 상호작용이 필요한 경우 선택하는 것이 좋다.
참고
'Spring > WebSocket' 카테고리의 다른 글
[Spring WebSocket] STOMP (0) | 2024.11.04 |
---|---|
[Spring WebSocket] SockJS (2) | 2024.11.04 |
[Spring WebSocket] WebSocket (0) | 2024.11.04 |