-
Notifications
You must be signed in to change notification settings - Fork 5
websocket protocol
WebSocket은 최초 연결 시 HTTP 기반 핸드셰이크를 수행합니다.
따라서 시그널링 서버와 WebSocket 연결을 맺기 위해서는 HTTP URL(host) 이 필요합니다.
일반적인 WebSocket 구현에서는 직접 쿼리를 구성해야 하지만,
본 시스템은 socket.io를 사용하므로 보다 간단하게 연결할 수 있습니다.
아래는 프론트엔드가 시그널링 서버와 WebSocket 연결을 맺을 때 사용하는 기본 코드입니다.
import { io } from "socket.io-client";
const socket = io(`${backend_url}/signal`, {
path: "/api/ws", // WEBSOCKET_PATH
transports: ["websocket"], // 서버가 websocket only
});WebSocket 연결에는 다음 3가지 요소가 반드시 필요합니다.
-
코드에서
${backend_url}에 해당합니다. -
REST API 호출 시에는
http://localhost:8080/api를 사용했지만, -
WebSocket 연결 시에는 실제 호스트 주소인
http://localhost:8080을 사용해야 합니다.
예시 (로컬 환경):
import { io } from "socket.io-client";
const socket = io("http://localhost:8080/signal", {
path: "/api/ws", // WEBSOCKET_PATH
transports: ["websocket"], // 서버가 websocket only
});📌 권장 사항
- 테스트 서버 / 운영 서버가 다르므로
-
backend_url은 반드시 환경변수로 관리하는 것을 권장합니다. - 해당 값만 공유해주시면 CI/CD 반영에는 문제가 없습니다.
-
path는 Socket.IO 핸드셰이크가 붙는 HTTP 경로입니다. - 실제 요청은 내부적으로 다음과 같은 형태로 전송됩니다.
http://localhost:8080/{path}/?EIO=4&transport=websocket- 테스트 서버에서는 이
path가 필수 요소이며, - 해당 값이 일치하지 않으면 WebSocket 연결이 실패합니다.
path: "/api/ws"- 본 시스템의 시그널링 WebSocket namespace는 다음과 같습니다.
/signal- namespace는 같은 WebSocket 서버 내에서 논리적으로 연결을 분리하기 위한 개념입니다.
- 모든 시그널링 관련 통신은
/signalnamespace를 통해 이루어집니다.
io("http://localhost:8080/signal", { ... });프론트엔드는 생성된 socket 객체를 useRef, 전역 상태,
싱글톤 등 연결이 유지되는 방식으로 관리해야 합니다.
아래 이벤트들은 프론트엔드에서 반드시 처리할 것을 권장합니다.
socket.on("connect", () => {
// 연결 완료
});
socket.on("disconnect", (reason) => {
// 서버 disconnect(true)로 끊길 수 있음
// 보통 방에 인원이 가득 차거나 연결이 불안정할때 생길 수 있습니다.
});
socket.on("connect_error", (err) => {
// 무슨 에러가 발생한 것입니다. 이를 헨드링 할 수 있습니다.
});
-
connect→ WebSocket 연결이 정상적으로 완료된 상태
→ 이 시점부터 시그널링 이벤트 송수신 가능
-
disconnect→ 서버 정책에 의해 강제로 끊길 수 있음
→
reason을 기반으로 사용자 알림 처리 가능 -
connect_error→ 인증 실패, 네트워크 오류 등
→ 재시도 또는 에러 UI 처리 가능
회원으로 접속한 경우,
WebSocket
핸드셰이크 과정에서 refresh_token으로 인해 access_token이 갱신되었을 때만
아래 이벤트가 서버 → 클라이언트로 전달됩니다.
socket.on("auth:access_token", ({ access_token }) => {
// access_token이 갱신된 경우에만 전달됨
});- 해당 이벤트는 항상 오는 것이 아닙니다
- 전달된다는 것은 access_token이 새로 발급되었음을 의미합니다.
회원 접속의 경우,
HTTP 핸드셰이크 단계에서 인증 정보를 함께 전달해야 합니다.
import { io } from "socket.io-client";
const socket = io("http://localhost:8080/signal", {
path: "/api/ws",
transports: ["websocket"],
withCredentials: true, // 쿠키 기반 인증 사용 시 필수
headers: {
Authorization: "Bearer <access_token>",
},
});-
비회원(게스트) 접속의 경우
headers,withCredentials를 설정하면 의도적으로 에러가 발생하도록 설계되어 있습니다. -
인증 관련 설정은 회원 접속 시에만 적용해야 합니다.
- 🧱 WebRTC (SFU) 기반 실시간 화상 음성 통화 아키텍처
- 🧱 코드에디터 실시간 Yjs 동기화 아키텍처
- 🧱 웹소켓 채팅 및 대용량 파일 전송 시스템 아키텍처
- 🏗️ 인프라 아키텍처
- 카카오 OAuth 과정에 state 도입
- 코드에디터 실시간 협업에 필요한 기술 정리
- 웹소켓 채팅 및 대용량 파일 전송 시스템 구현 기록
- Signaling Server – Client Protocol
- [FE] 통화 음질 개선
- [FE] React-Konva 라이브러리 환경에서의 SVG 렌더링 이슈 및 해결 방안
- [FE] canvas 재렌더링 문제 및 개선
- [FE] Redo Undo 시 아이템 중복 생성 문제 및 개선
- [FE] React Profiler React Compiler로 렌더링 분석 및 최적화
- [FE] next image의 비동기 로딩에 따른 Layout Shift와 채팅 스크롤 동기화 개선
- [BE] 회의 단위 협업 툴 상태 공유 문제 해결 과정
- [BE] Yjs 기반 문서 동기화 문제 해결 과정
- [n8n] n8n으로 코드리뷰 개선 및 보완하기
- (deprecated) [FE] 코드에디터 소켓 연결 및 실시간 로직 연동