MB[Message Bridge]

모든 연결의 중심, 메시지브릿지.

메시지 브릿지 엔진은 WebSocket 기반의 실시간 통신을 중심으로,단순한 연결이 아닌 연결의 상태와 수명을 함께 관리하도록 설계되었습니다.

Engine Specification

데이터 동기화 원칙

TECH STACK

WebSocket Protocol (WSS)

보안 인증서(SSL)가 적용된 전용 포트를 사용하여 서버와 클라이언트 간의 암호화된 양방향 통신 채널을 형성합니다.

Event-Driven Architecture

폴링(Polling) 방식이 아닌 이벤트 발생 시점에 즉시 데이터를 푸시하여 네트워크 부하를 줄이고 반응 속도를 극대화합니다.

엔진 작동 원리

  • 01 브라우저 접속 시 고유 ID(MB_ID/IP) 생성 및 서버 연결
  • 02 서버로부터 전체 접속자 Map 데이터를 JSON으로 수신
  • 03 UI 핸들러(updateDisplay)를 통해 화면 실시간 렌더링

Developer API Guide

connectWebSocket()

서버와 첫 악수를 나눕니다. 도메인별 그룹을 생성하여 해당 채널의 데이터를 동기화하기 시작합니다.

성공 시 'join' 이벤트를 자동 발생시킵니다.
sendEvent(jsonData)

서버로 데이터를 보낼 때 사용합니다. 채팅 메시지, 위치 정보, 클릭 로그 등을 JSON 형태로 전송합니다.

JSON.stringify를 통해 안전하게 직렬화됩니다.
gracefulDisconnect()

사용자가 탭을 닫거나 다른 페이지로 갈 때 호출됩니다. 서버에 "나 나간다"고 확실히 알려줍니다.

sendBeacon 기술을 사용하여 종료 전송률을 높입니다.

Engine Architecture

1. 신원 확보 (Identity)

회원 아이디나 IP를 추출하여
고유한 통신 키를 생성합니다.

2. 실시간 동기화 (Sync)

웹소켓 통로를 통해 서버의
명단 데이터를 0.1초 만에 받습니다.

3. 가비지 정리 (Cleanup)

브라우저 종료 시 흔적을 남기지 않고
안전하게 연결을 해제합니다.

Line-by-Line Guide

Environment Setup
const domain = window.location.hostname;
const MB_ID = "<?php echo $member['mb_id']; ?>";
const USER_IP = "<?php echo $_SERVER['REMOTE_ADDR']; ?>";
const myKey = MB_ID || USER_IP;
STEP 01
환경 변수 및 식별자 설정

"현재 접속 중인 도메인과 PHP 서버로부터 회원 ID, IP 정보를 받아와 사용자만의 고유 키(Key)를 생성합니다."

State Management
let ws;
let activeUsers = new Map();
let userListString = "";
STEP 02
실시간 데이터 저장소 준비

"웹소켓 객체와 현재 접속 중인 유저들의 정보를 담을 Map(명단) 객체, 그리고 화면에 뿌려줄 문자열 변수를 초기화합니다."

Connection Establishment
function connectWebSocket() {
  ws = new WebSocket('wss://designonex.com:14147...');

  ws.onopen = () => {
    sendEvent({type: "join", ...});
  };
}
STEP 03
서버 연결 및 입장 신고

"지정된 서버 주소로 전화를 걸듯 연결을 시도하고, 연결이 성공(onopen)하면 즉시 서버에 '저 들어왔어요'라고 알립니다."

Initial Sync
if (data.type === "init") {
  activeUsers.clear();
  for (const u of data.users) {
    activeUsers.set(u.mb_id || u.ip, u);
  }
}
STEP 04
전체 명단 초기화 (Init)

"처음 접속했을 때 서버가 보낸 '현재 여기 있는 모든 사람들'의 리스트를 받아 내 장부에 깨끗하게 받아 적습니다."

Real-time Updates
else if (type === "join" || type === "update") {
  const key = data.mb_id || data.ip;
  activeUsers.set(key, data);
}
STEP 05
실시간 변화 감지 (Join/Update)

"누가 새로 들어오거나 정보가 바뀌면, 해당 유저의 식별자를 찾아 명단에 새 정보를 덮어씁니다."

Auto Recovery
ws.onclose = () => {
  setTimeout(connectWebSocket, 2000);
};
ws.onerror = () => { ws.close(); };
STEP 06
끈질긴 연결 유지

"인터넷이 끊기거나 서버가 잠시 죽더라도, 2초마다 계속해서 재연결을 시도하여 실시간성을 보장합니다."

Data Transmitter
function sendEvent(jsonData) {
  if (ws && ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify(jsonData));
  }
}
STEP 07
데이터 안전 전송
DX

클라이언트 개발자 꿀팁

1

자동 재연결: 인터넷이 잠시 끊겨도 2초 뒤에 알아서 재연결하니 걱정 마세요.

2

Map 객체 사용: 리스트 대신 Map을 쓴 이유는 수만 명의 접속자 중 특정 한 명을 단 0.0001초 만에 찾기 위해서입니다.

3

Visibility 감시: 사용자가 화면을 보지 않을 땐 연결을 끊어 스마트폰 배터리를 지켜줍니다.

4

보안(WSS): 모든 데이터는 암호화되어 전송되므로 해킹 걱정 없이 안전합니다.

Full Source Implementation
// 1. 환경 변수 설정
const domain = window.location.hostname;
const MB_ID = "<?php echo $member['mb_id']; ?>";
const USER_IP = "<?php echo $_SERVER['REMOTE_ADDR']; ?>";
const myKey = MB_ID || USER_IP;

let ws;
let activeUsers = new Map(); 
let userListString = "";

// 2. 웹소켓 연결 엔진
function connectWebSocket() {
    ws = new WebSocket('wss://designonex.com:14147/?group=' + encodeURIComponent(domain));

    ws.onopen = () => {
        sendEvent({type: "join", mb_id: MB_ID, ip: USER_IP});
    };

    ws.onmessage = (event) => {
        let data;
        try { data = JSON.parse(event.data); } catch { return; }

        if (data.type === "init") {
            activeUsers.clear();
            for (const u of data.users) {
                const key = u.mb_id || u.ip || Math.random();
                activeUsers.set(key, u);
            }
        }
        else if (data.type === "join" || data.type === "update") {
            const key = data.mb_id || data.ip || Math.random();
            activeUsers.set(key, data);
        }
        else if (data.type === "leave") {
            const key = data.mb_id || data.ip;
            activeUsers.delete(key);
        }

        rebuildUserString();
        if (typeof updateDisplay === "function") {
            updateDisplay(activeUsers, data); 
        }
    };

    ws.onclose = () => {
        setTimeout(connectWebSocket, 2000); 
    };

    ws.onerror = () => { ws.close(); };
}

// 3. 메시지 전송 및 종료 처리
function sendEvent(jsonData) {
    if (ws && ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify(jsonData));
    }
}

function gracefulDisconnect() {
    const leaveData = {type: "leave", mb_id: MB_ID, ip: USER_IP};
    if (ws && ws.readyState === WebSocket.OPEN) {
        try { ws.send(JSON.stringify(leaveData)); ws.close(); } catch(e) {}
    }
    try {
        const blob = new Blob([JSON.stringify(leaveData)], {type: "application/json"});
        navigator.sendBeacon("/ws-leave", blob);
    } catch(e) {}
}

window.addEventListener("beforeunload", gracefulDisconnect);
window.addEventListener("pagehide", gracefulDisconnect);
document.addEventListener("visibilitychange", () => {
    if (document.visibilityState === "hidden") gracefulDisconnect();
});

function rebuildUserString() {
    userListString = Array.from(activeUsers.values())
        .map(u => u.mb_id || u.ip)
        .join(" | ");
    requestAnimationFrame(() => {
        if (typeof updateDisplay === "function") updateDisplay(activeUsers);
    });
}

connectWebSocket();
Production Ready

실시간 동기화
엔진 전체 소스

"위 소스코드는 도메인 식별부터 세션 종료(Beacon API)까지 포함된 완성형 스크립트입니다. 별도의 설정 없이 연동 가능합니다."

  • 양방향 통신: WebSocket 프로토콜 지원
  • 메모리 최적화: Map 객체 기반 관리
  • 예외 처리: 모바일 절전/종료 완벽 대응

Important Note

그누보드 환경에서 $member 변수가 유효한 위치에 삽입되어야 정상 작동합니다.

DX
DESIGNONEX

단 하나의 차별화된 경험을 만든다
기술과 예술이 결합된 최상의 디지털 솔루션을 경험해 보세요.

Information

상호명: 디자인원엑스 (DESIGNONEX)

대표자: 김일형

사업자번호: 123-36-98558

통신판매번호 : 2025-안양만안-574

에스크로 서비스 등록번호

제 A07-20260105-0033 호

Contact

이메일: designonex@naver.com

연락처: 010-6210-0381

© 2025 DESIGNONEX. ALL RIGHTS RESERVED.