카테고리 없음

WebSocket 개념 정리

kjw81024 2026. 8. 11. 15:29

국비지원 부캠 수업을 들을 때 Websocket 을 다루는 역할을 맡지 않아서 이번에 인턴하면서 Websocket 개념이랑 ...

몰라서 생긴 여러 트러블슈팅을 정리하고 넘어가기 

 

이번에 프로젝트에서 사용한 이유는 

crowd count, 영상 CCTV 처럼 송출 이 필요한데 그 때마다 client (dashboard) 에 즉시 알려줘야 하기 땜누에 HTTP polling 보다 효율적인 방식인 Websocket 사용이었다 


특징

 

비교 대상: HTTP 

HTTP 응답 이후 연결이 끊김 (매번 새로 요청, 검증)
keyword: 비연결, 무상태 
WebSocket 한 번 연결하면 계속 유지 
server -> client 방향으로 먼저 데이터 보낼 수 있음 (양방향)

ws:// 랑 wss:// 는 Http 랑 동일하게 암호화 여부 (s 가 붙은게 security)

만약 사용하는 서버가 https://tempurl.co.kr 로 서빙되면 반드시 wss:// 를 사용하기 

아니면 브라우저가 Mixed Content 에러를 띄운다고 함 (Https page 에서 암호화 안 된 연결을 시도하는거니까!)

 

연결 과정을 Handshake 라고 부르는 듯 함 귀엽다.!! 악수라니 

 

1. client 가 일반 HTTP 요청을 보낼 때 header 에 Upgrade: websocket 이 포함됨 

프론트 코드에서 아래 한 줄을 실행하면 

const ws = new WebSocket("wss://temp.url.co.kr/ws/crowd");

브라우저가 

GET /ws/crowd HTTP/1.1
Host: tmep.url.co.kr
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xxxxx
Sec-WebSocket-Version: 13

요런 헤더가 붙은 HTTP 요청을 만들어서 보냄 

이 설정이 NGINX 에서 해주는 아래 설정

location /ws/ {
    proxy_pass http://localhost:8000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Upgrade 요청을 붙여주기 

 

2. 서버가 101 Switching Protocols 응답하면 그때부터 HTTP 연결이 WebSocket 연결로 upgrade 됨 

 

3. 이후로 계속 열린 채널로 메시지 주고 받기 
(매번 요청을 새로 쓸 필요 없어짐)


추가

기억해둘만한 WebSocket 객체의 기본 이벤트 

ws.onopen = () => console.log("연결됨");
ws.onmessage = (event) => console.log("데이터 옴:", event.data);
ws.onerror = (error) => console.log("에러:", error);
ws.onclose = () => console.log("연결 끊김");

특히 onmessage 에서 event.data 가 문자열로 오기 때문에 JSON.parse(data) 해줘야함!!!

 

추가로 onclose 되면 재시도를 해줘야하기 때문에 특정 시간 이후에 재시도 하는 로직을 추가해주는게 좋다 

ws.onclose = () => {
  setTimeout(() => connectWebSocket(), 3000); // 3초 뒤 재시도
};

 

++  백엔드 서버 하나랑만 연결 가능함 - 한 번 연결된 백엔드 인스턴스랑 계속 붙어있어야한다 

 

WebSocket 프로토콜에는 ping/pong 이 있는데 java script 브라우저 에는 native ping 을 보내는 api 가 X

-> 근데 NGINX 의 proxy_read_timeout 은 backend 로부터 아무런 데이터가 안오는걸 기준으로 count 를 세기 때문에 

가짜메시지... 평범한 메시지를 주기적으로 보내는 방식 사용 

const ws = new WebSocket("wss://temp.url.co.kr/ws/crowd");

setInterval(() => {
  if (ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({ type: "ping" }));
  }
}, 30000); // 30초마다 살아있다고 알림

client (front) 에서 이렇게 보내주면

@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
    if (message.getPayload().contains("\"type\":\"ping\"")) {
        session.sendMessage(new TextMessage("{\"type\":\"pong\"}"));
        return;
    }
    // 나머지 로직...
}

Spring Boot 쪽 WebSocket Handler 가 이렇게 받아서... 연결이 안 끊기게 해줌