본문 바로가기
정리

WebSocket

by dyddyd0 2025. 4. 12.

 

웹소켓이란?

WebSocket은 클라이언트와 서버 간에 지속적인 연결을 유지하면서 실시간 양방향 통신을 가능하게 해주는 프로토콜.

HTTP와는 다르게, 한번 연결이 맺어지면 클라이언트나 서버 어느 쪽이든 자유롭게 데이터를 주고받을 수 있음.

  • HTTP: 기본 포트는 80번
  • HTTPS: 기본 포트는 443번
  • WebSocket (ws): 기본 포트는 80번
  • WebSocket Secure (wss): 기본 포트는 443번
  • 초기 연결은 HTTP로 시작 → 그 후 WebSocket 프로토콜로 업그레이드

 

얼마 전 구현한 웹소켓 채팅을 예를 들어보자.

    const ws = new WebSocket("ws://" + tempLocation + "/ws/chat");
    
    // 여기서 tempLocation 에는 "localhost:8080" 을 넣어주었다.

위 코드에서 웹소켓 연결을 열어주며 new WebSocket을 생성할 때 ws:// 를 붙여주었다.

ws:// 는 웹소켓 연결을 만들 때 웹소켓 프로토콜임을 명시해 주기 위해 반드시 필요함.

코드의 의미는 웹소켓 서버가 localhost:8080 포트에서 웹소켓 연결을 기다리고 있다고 해석가능하다.

 

백엔드 서버에서는 다음과 같이 WebSocketConfig 클래스를 만들어 주었는데,

이 클래스파일을 통해 웹소켓 설정을 하는 것이다.

 

웹소켓은 기본적으로 HTTP는 80번 포트에서 실행되지만, 스프링부트가 기본적으로 웹 서버를 8080번 포트에서 구동하고 있다. 즉, localhost:8080은 HTTP 서버의 포트이고, 웹소켓은 이 서버를 통해 연결된다.

package jpabasic.toyvaserver.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration // 스프링 설정 클래스임을 명시
@EnableWebSocket // WebSocket 기능을 활성화
public class WebSocketConfig implements WebSocketConfigurer {

    private final WebSocketHandler webSocketHandler;

    public WebSocketConfig() {
        webSocketHandler = new ChatWebSocketHandler();
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // WebSocket 엔드포인트를 "/ws/chat"으로 설정
        // (ws://localhost:8080/ws/chat 로 요청 들어오면, WebSocket 통신 시작)
        registry.addHandler(webSocketHandler, "/ws/chat")
                .setAllowedOrigins("http://localhost:3000"); // ws 에 대한CORS 허용
    }
}

 

 

웹소켓 연결 과정은?

 

웹소켓 핸드셰이크를 통해 연결함.

 

웹소켓 연결은 HTTP 프로토콜을 기반으로 시작한다.

초기 요청은 HTTP 요청으로 전송되며, 이를 웹소켓 핸드셰이크라고 부름.

 

1-1 클라이언트에서 서버로 요청
    클라이언트가 웹소켓 서버에 연결을 요청할 때, HTTP GET 요청을 보냄.
    이 요청에는 웹소켓 연결을 시작하고자 하는 의도가 담겨있음.

 

예를 들어 const socket = new WebSocket("ws://localhost:8080/ws/chat");

 

웹소켓 클라이언트는 ws://localhost:8080/ws/chat로 아래 헤더들을 포함한 HTTP GET 요청을 보낸다.

  • Upgrade: websocket: HTTP 프로토콜에서 웹소켓 프로토콜로 업그레이드하려는 요청
  • Connection: Upgrade: 연결을 업그레이드하려는 요청
  • Sec-WebSocket-Key: 클라이언트가 보내는 임의의 키 값 (서버가 응답을 생성할 때 사용)
  • Sec-WebSocket-Version: 웹소켓 프로토콜 버전

1-2 서버의 응답

    서버는 클라이언트의 요청을 처리하고, HTTP 응답을 보내면서 웹소켓 연결을 승인한다.

    서버는 요청 헤더의 정보를 바탕으로 웹소켓 연결을 설정하고, 101 Switching Protocols 상태 코드로 응답함.

   

서버의 응답 헤더 예시:

  • HTTP/1.1 101 Switching Protocols: 웹소켓 연결을 수락하는 응답 상태 코드
  • Upgrade: websocket: 서버가 HTTP에서 웹소켓으로 업그레이드되었음을 알림
  • Connection: Upgrade: 연결이 업그레이드되었음을 알림
  • Sec-WebSocket-Accept: 서버가 클라이언트의 Sec-WebSocket-Key에 대한 응답을 포함 (해시 값)

 

2. 연결 완료되고 양방향 통신시작
    핸드셰이크가 성공적으로 완료되면, HTTP 연결이 웹소켓 연결로, 지속적인 양방향 연결로 전환됨.
    이 상태에서 클라이언트와 서버는 데이터를 실시간으로 주고받을 수 있게 됨.

 

3. 클라이언트와 서버가 실시간으로 메시지 주고받음

 

4. 클라이언트 혹은 서버가 연결 종료하며 종료됨.

 

 

[ ]

 


웹소켓은 어디에 사용될까?

웹소켓은 다음과 같이 실시간성이 중요한 서비스에서 주로 사용함

  • 채팅 애플리케이션 (1:1, 그룹 채팅)
  • 실시간 알림 (푸시 알림, SNS 알림 등)
  • 실시간 협업 도구 (예: Google Docs)
  • 주식/코인 시세 실시간 반영
  • 온라인 게임 (실시간 위치 전송 등)
  • 라이브 방송/댓글 시스템

 

채팅을 왜 웹소켓으로 구현할까?

우선 채팅은 실시간 양방향 통신이 핵심인 서비스인데,

웹소켓은 실시간 양방향 통신에 적합한 기술로, 지연시간을 최소화하고 효율적으로 데이터를 주고받을 수 있게 해 준다.

 

HTTP 방식은 주기적인 요청을 보내는 방식으로 실시간성을 구현하는 데 한계가 있지만, 웹소켓은 연결을 유지한 채 클라이언트와 서버가 자유롭게 메시지를 주고받을 수 있어 실시간 서비스에서 중요한 역할을 함.

채팅 같은 서비스에서는 빠르고 즉각적인 반응이 요구되므로, 웹소켓이 거의 필수임.

 

  • 비동기 처리:
      웹소켓은 비동기적으로 데이터를 처리할 수 있기 때문에, 클라이언트와 서버 간의 실시간 통신이 가능.
      클라이언트가 메시지를 보낼 때마다 서버가 그 메시지를 바로 받게 되며,
      서버는 그 메시지를 지체 없이 다른 클라이언트로 전송가능.
      ->
      서버가 클라이언트의 요청 안 기다리고, 필요한 순간에 메시지를 자동으로 푸시할 수 있는 구조라서, 실시간성 굿굿.
  • 속도와 효율성:
    예를 들어, 채팅 애플리케이션에서 수많은 사용자가 동시에 메시지를 주고받을 때, 웹소켓은 메시지 전송 속도응답 속도를 모두 개선할 수 있음. 이를 통해 수많은 사용자에게 실시간으로 메시지를 전달할 수 있어, 전체 시스템의 확장성 또한 좋아짐.
  • HTTP 방식의 한계:
      일반적인 HTTP는 요청-응답 구조라, 실시간으로 클라이언트에게 알리는 건 힘듦.
      클라이언트가 계속 요청(polling) 해야 하는 비효율적인 방식
  • 웹소켓은 연결 유지:
      한 번 연결 후, 서버가 클라이언트에게 알아서 메시지를 push 할 수 있음.
  • 지연시간 최소화:
      연결 유지 상태에서 빠르게 데이터를 주고받을 수 있음.

웹소켓 없이도 채팅 구현 가능할까?

이론적으로는 가능 하지만 비효율적이다.
대표적인 대안으로 Polling 방식 그리고 SSE (Server-Sent Events) 방식으로 구현 가능.

 

1. Long Polling
클라이언트가 일정 주기로 서버에 메시지를 요청하는 방식.
실시간성이 떨어지고, 너무 자주 요청하면 서버에 불필요한 부하가 발생함

  • 클라이언트가 요청을 보내고, 서버가 응답을 최대한 늦게 보내는 방식
  • 클라이언트가 응답을 받으면 곧바로 다시 요청 → 무한 루프
  • 단점: 서버 자원 소모 많고, 반응 속도 떨어짐 

 

2. Short Polling
서버가 응답을 보낼 때까지 요청을 보류하고, 응답 후 클라이언트가 다시 요청을 보내는 방식.
실시간성은 어느 정도 확보되지만, 매번 요청-응답을 반복하므로 서버 리소스를 많이 소모함

  • 주기적으로 일정 시간마다 요청 → 새로운 메시지 있으면 응답
  • 단점: 실시간성 떨어지고, 트래픽 낭비 심함

 

3. SSE (Server-Sent Events)
서버에서 클라이언트로만 데이터를 푸시할 수 있는 방식.
단방향 통신에만 적합하고, 클라이언트에서 서버로 보내는 메시지는 별도의 HTTP 요청으로 처리해야 함

  • 서버 → 클라이언트 방향으로만 단방향 실시간 전송 가능
  • 양방향 채팅에는 부적합

그래서 결론적으로 실시간성과 효율성을 고려하면 웹소켓이 가장 적합하다~

 

 

 

 

반응형

'정리' 카테고리의 다른 글

CICD와 무중단 배포  (0) 2025.04.15
java, spring 개념 정리  (0) 2025.04.13
OSI 7계층과 존재 이유, TCP/IP 4계층  (0) 2025.04.11
CORS와 SOP  (0) 2025.04.10
Https와 SSL HandShake  (0) 2025.04.09