์ฌ์ฉ์ A์ B๊ฐ ์๋ก 100m ์ด๋ด์ ์์ผ๋ฉด ์ค์๊ฐ์ผ๋ก ๊ฐ์ง๋๋ ๊ธฐ๋ฅ์ ๋ง๋ค๊ธฐ ์ํด WebSocket์ ๋์ ํ์ต๋๋ค.
์ฒซ๋ฒ์งธ๋ก ์น์์ผ์ ์ธํ ํ๊ณ ์ฐ๊ฒฐํ๋ ์ด๊ธฐ์ธํ ๊ณผ์ ์ ๋๋ค.

๐งญ ์ ์ฒด ๋ชฉํ ๊ธฐ๋ฅ
‘๋ฌด๋ฌผ’ ํ๋ก์ ํธ๋ ๋ค์ ๊ธฐ๋ฅ์ ๋ชฉํ๋ก ํ๊ณ ์์ต๋๋ค.
- ๋ด ์ฃผ๋ณ 100m ์ด๋ด์ ์ฌ์ฉ์ ํ์
- ์ค์๊ฐ์ผ๋ก ์ฌ์ฉ์ ์์น ๊ฐฑ์ ๋ฐ ์๊ฐํ
- ์ฌ์ฉ์ ํด๋ฆญ ์ ์ค์๊ฐ ์๋ฆผ ์ ์ก
- ๋ฉํฐ ๋๋ฐ์ด์ค ๊ฐ ํต์ ๊ฐ๋ฅ (์: ํธ๋ํฐ ↔ ๋ ธํธ๋ถ)
์ด๋ฌํ ๊ธฐ๋ฅ๋ค์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉ์ ๊ฐ์ ์ค์๊ฐ ๋ฐ์ดํฐ ์ก์์ ์ด ํ์ํฉ๋๋ค.
๐ก ์ WebSocket์ธ๊ฐ?
- HTTP๋ ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญํด์ผ ์๋ฒ๊ฐ ์๋ตํ๋ ๊ตฌ์กฐ๋ผ, ์ค์๊ฐ ํต์ ์ด ์ด๋ ต๊ณ
- WebSocket์ ์๋ฐฉํฅ ํต์ ์ ํตํด ์๋ฒ → ํด๋ผ์ด์ธํธ๋ก๋ ๋ฉ์์ง๋ฅผ ์ฆ์ ๋ณด๋ผ ์ ์๋ค๋ ์ฅ์ ์ด ์์ต๋๋ค.
ํ๋ก์ ํธ ๋ชฉํ ๊ธฐ๋ฅ์ด ์ฌ์ฉ์์ ์์น ์ ๋ณด๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ์๋ฒ์ ๋ณด๋ด๊ณ , ์๋ฒ๋ ์ค์๊ฐ์ผ๋ก ๋ค๋ฅธ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ๋ฌํด์ผ ํ์ต๋๋ค.
๊ฒฐ๋ก ์ ์ผ๋ก WebSocket์ ์ค์๊ฐ ์์น ๊ธฐ๋ฐ ํต์ ์ ์ต์ ํ๋ ๊ธฐ์ ์ด์์ต๋๋ค.
์ฒ์ ์๋๋ ๋ธ๋ฃจํฌ์ค, ํ์ง๋ง ๊ฒฐ๊ตญ์ ์๋/๊ฒฝ๋๋ก ์ ํํ ๊ณผ์
์ด๊ธฐ ๊ธฐํ ๋จ๊ณ์์๋ "๊ทผ๊ฑฐ๋ฆฌ ํต์ "์ด๋ผ๋ ๋จ์ด ๊ทธ๋๋ก, ๊ธฐ๊ธฐ ๊ฐ์ ๋ฌผ๋ฆฌ์ ๊ทผ์ ์ ํ์งํ๋ ๋ฐฉ๋ฒ์ผ๋ก Bluetooth Low Energy (BLE) ๊ธฐ๋ฐ ์ ๊ทผ์ ๊ณ ๋ คํ์ต๋๋ค. ํ์ง๋ง ๊ตฌํ๊ณผ ์กฐ์ฌ ๊ณผ์ ์์ ์ฌ๋ฌ ํ์ค์ ์ธ ์ ์ฝ์ผ๋ก ์ธํด GPS ๊ธฐ๋ฐ ์๋/๊ฒฝ๋ ๊ฑฐ๋ฆฌ ๊ณ์ฐ ๋ฐฉ์์ผ๋ก ์ ํํ๊ฒ ๋์์ต๋๋ค.
- โ ๋ธ๋ฃจํฌ์ค๋ ๋ธ๋ผ์ฐ์ ์ง์ ์ ์ฝ์ด ํผ (ํนํ ๋ชจ๋ฐ์ผ์์)
- โ ์น ๊ธฐ๋ฐ ์ฑ์์ ๊ถํ ์ฒ๋ฆฌ์ ์ค์บ API ์ ์ฝ์ด ํผ
- โ ์์น ๊ธฐ๋ฐ ์ ๊ทผ์ ๋ชจ๋ฐ์ผ ์น, ์น ์ฑ, PWA์์ ๋ชจ๋ ์์ ์ ์ผ๋ก ์ง์
- โ GPS ์ ๋ณด๋ ์ฌ์ฉ์๊ฐ ๊ฑฐ๋ฆฌ ๊ณ์ฐ์ด ๋ช ํํจ
โ ๋ธ๋ฃจํฌ์ค๋ฅผ ํฌ๊ธฐํ ์ด์ 1: ๋ธ๋ผ์ฐ์ ์ง์์ ํ๊ณ
| Chrome (Desktop) | โ ์ง์ | ์คํ์ ๊ธฐ๋ฅ์ผ๋ก ํ์ฑํ ํ์ |
| Chrome (Android) | โ ์ ํ์ ์ง์ | ๊ธฐ๊ธฐ/OS์ ๋ฐ๋ผ ์ฐจ์ด ์์ |
| Safari (iOS) | โ ๋ฏธ์ง์ | Web Bluetooth ๋ฏธ์ง์ (2025๋ ํ์ฌ ๊ธฐ์ค) |
| Firefox | โ ๋ฏธ์ง์ | ๋ณด์ ๋ฌธ์ ๋ก ๊ธฐ๋ณธ์ ์ผ๋ก ์ฐจ๋จ |
| Samsung Internet | โ ๋ฏธ์ง์ | Web Bluetooth ์ง์ํ์ง ์์ |
์ฐ์ ๋ธ๋ฃจํฌ์ค๋ ์น๋ช ์ ์ผ๋ก ๋ธ๋ผ์ฐ์ ๋ณ ์ ์ฝ์ด ์ปธ์ต๋๋ค.
iOS Safari์์๋ ์์ ๋์ํ์ง ์์ผ๋ฉฐ, ์๋๋ก์ด๋๋ผ๊ณ ํด๋ WebView, PWA ๋ฑ์์ BLE ์ ๊ทผ์ด ๋ถ์์ ํ๊ฑฐ๋ ๋ถ๊ฐ๋ฅํ ๊ฒฝ์ฐ๊ฐ ๋ง์์ต๋๋ค.
์ ํฌ๋ ์น ๊ฐ๋ฐ์ด์ง๋ง ๋ชจ๋ฐ์ผ ํ๋ฉด๋ง ๊ฐ๋ฐํ๊ธฐ๋ก (์๊ฐ ์ ์ฝ ์ ๋ฐ์ํ์ ์๋ต) ํ๊ธฐ ๋๋ฌธ์ ๋ธ๋ผ์ฐ์ ์ ์ฝ์ด ํฐ ๋ธ๋ฃจํฌ์ค๋ ๊ณค๋ํ์ต๋๋ค.
โ ๋ธ๋ฃจํฌ์ค๋ฅผ ํฌ๊ธฐํ ์ด์ 2: ๊ถํ ๋ฐ ๊ธฐ๊ธฐ ํ์ ๋ณต์ก์ฑ
๋ ๋ธ๋ฃจํฌ์ค๋ก ๋ค๋ฅธ ์ฌ์ฉ์์ ์์น๋ฅผ ์ธ์ํ ๋ ํด๋น ๊ธฐ๊ธฐ๋ฅผ ์ธ์ํ๋ ๊ณผ์ ์์ ๋ณต์กํ๋ค๊ณ ๋๊ผ์ต๋๋ค.
๋ธ๋ฃจํฌ์ค๋ฅผ ์ฐ์ ์ ์ผ๋ก ๊ณ ๋ คํ์ ๋น์, ์๋์ ํ๋ก์ฐ๋ฅผ ๋ฐ๋ผ์ผ ํ์ต๋๋ค.
-
- ์ฌ์ฉ์๊ฐ ๊ธฐ๊ธฐ ๊ฒ์ ๊ถํ์ ์๋์ผ๋ก ํ์ฉ
- ์ค์บ ๊ฐ๋ฅํ BLE ๊ธฐ๊ธฐ๊ฐ ํน์ ์๋น์ค UUID๋ฅผ ๋ธ๋ก๋์บ์คํธํ๊ณ ์์ด์ผ ํจ
- ํด๋น ๊ธฐ๊ธฐ๋ฅผ ์ค์บํ๊ณ ์ฐ๊ฒฐํ๊ฑฐ๋, ์ ๋ณด๋ฅผ ์ฝ์ด์ผ ํจ
- ๊ทธ๋ฌ๋ ์ ํฌ์ ๋ชฉํ๋ '๋๊ตฐ๊ฐ ๊ทผ์ฒ์ ์๋ค'๋ ๊ฒ์ ์ฆ์ ๊ฐ์งํ๋ ๊ฒ์ด์๊ธฐ ๋๋ฌธ์, ์ ๊ณผ์ ์ ๋๋ฌด ๋ฒ๊ฑฐ๋กญ๊ณ ,
- ๊ธฐ๊ธฐ๋ง๋ค BLE ๋ธ๋ก๋์บ์คํธ ๋ฐฉ์์ด ๋ค๋ฅด๊ณ
- ์ฌ์ฉ์๊ฐ ์ฑ์ ๋ฐฑ๊ทธ๋ผ์ด๋์ ๋ ๊ฒฝ์ฐ BLE ์ธ์์ด ์๋ํ์ง ์์
- ๊ธฐ๊ธฐ ๊ฐ ํ์ด๋ง์ด๋ BLE Advertising ์ธํ ๋ ํ์ํด ์ฌ์ฉ์ UX ์ ํ ์์ธ์ด ๋ง์์ต๋๋ค
๋ฐ๋ฉด์ ์๋/๊ฒฝ๋๋ ๋ธ๋ผ์ฐ์ ํธํ์ฑ์ด ์๋์ ์ผ๋ก ์ข๊ณ , ์ค์๊ฐ ๊ฑฐ๋ฆฌ ๊ณ์ฐ์ด ์์ ํ๊ธฐ ๋๋ฌธ์ ์๋/๊ฒฝ๋ GPS ๊ธฐ๋ฐ ๊ฑฐ๋ฆฌ ๊ณ์ฐ ๋ฐฉ์์ ์ต์ข ์ ์ผ๋ก ์ ํํ์ต๋๋ค.
| ๋ธ๋ผ์ฐ์ ํธํ์ฑ | โ ๋ชจ๋ ์ต์ ๋ธ๋ผ์ฐ์ ์์ ์ง์ (PWA ํฌํจ) |
| ๊ถํ ์ฒ๋ฆฌ | โ ์ฌ์ฉ์ ์์น ๊ถํ๋ง ์์ฒญํ๋ฉด ์ฌ์ฉ ๊ฐ๋ฅ |
| ๊ฑฐ๋ฆฌ ์ธก์ | โ ์๋/๊ฒฝ๋๋ฅผ ํตํด ๋ช ํํ ๊ฑฐ๋ฆฌ ๊ณ์ฐ ๊ฐ๋ฅ |
| ์ค์๊ฐ์ฑ | โ WebSocket๊ณผ ๊ฒฐํฉํด ์ค์๊ฐ ๊ฑฐ๋ฆฌ ๊ธฐ๋ฐ ๋งค์นญ ๊ฐ๋ฅ |
๐ง WebSocket ์ด๋ค ๊ธฐ์ ์คํ์ผ๋ก ๊ฐ๋ฐํ ๊น?
ํ๋ก ํธ์๋๋ ์ด๋ฏธ NextJS (typescript ๊ธฐ๋ฐ) ๋ก ๊ตฌ์ฑ๋์ด ์์๊ณ , ํด๋ผ์ด์ธํธ์ ์๋ฒ ๋ชจ๋ JS/TS ์ํ๊ณ๋ฅผ ๊ณต์ ํ๋ฉด ํตํฉ ์ ์ง๋ณด์๊ฐ ์ฌ์ ๊ธฐ ๋๋ฌธ์, WebSocket ์๋ฒ ๊ฐ๋ฐ ์ ๋ค์๊ณผ ๊ฐ์ด ์ ํํ์ต๋๋ค.
- Node.js + Express: ๋น ๋ฅธ ๊ฐ๋ฐ๊ณผ ๋์ ์ปค์คํฐ๋ง์ด์ง ๊ฐ๋ฅ
- ws ๋ผ์ด๋ธ๋ฌ๋ฆฌ: Node.js์์ ๊ฐ์ฅ ๋๋ฆฌ ์ฐ์ด๋ WebSocket ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์ด์ธ์๋ ๋ฐฐํฌ๋ Render๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
WebSocket ์๋ฒ๊ฐ ์ง์์ ์ผ๋ก ์ด๋ ค ์์ด์ผ ํ๊ณ , ๋ฌด๋ฃ ์๊ธ์ ์์๋ NodeJS ์๋ฒ ๋ฐฐํฌ๊ฐ ๊ฐํธํ๊ธฐ ๋๋ฌธ์ Render ๋ฐฐํฌ๋ฅผ ์ ํํ์ต๋๋ค.
๐ ์ด๊ธฐ WebSocket ์๋ฒ ์ธํ
์ฒ์์๋ ๊ฐ์ฅ ๊ฐ๋จํ ๊ตฌ์กฐ๋ก WebSocket ์๋ฒ๋ฅผ ๊ตฌ์ฑํด๋ดค์ต๋๋ค. ํน๋ณํ ๋น์ฆ๋์ค ๋ก์ง ์์ด, ์ฐ๊ฒฐ๋ ๋ชจ๋ ํด๋ผ์ด์ธํธ๋ผ๋ฆฌ ๋ฉ์์ง๋ฅผ ๋ธ๋ก๋์บ์คํธํ๋ ๊ตฌ์กฐ์ ๋๋ค.
๋ชฉํ ์คํ ๊ฒฐ๊ณผ ์์
- ๋ธ๋ผ์ฐ์ ํญ A์์ ๋ฉ์์ง๋ฅผ ๋ณด๋ → ํญ B, C์์๋ ์ฆ์ console.log๋ก ์ถ๋ ฅ๋จ
1๏ธโฃ ์ด๊ธฐ ์๋ฒ ์ฝ๋ ๊ตฌ์ฑ
const express = require("express");
const http = require("http");
const WebSocket = require("ws");
const cors = require("cors");
const app = express();
app.use(cors()); // CORS ํ์ฉ
const server = http.createServer(app); // HTTP ์๋ฒ ๋ํ
const wss = new WebSocket.Server({ server }); // WebSocket ์๋ฒ ์์ฑ
const clients = new Set(); // ์ฐ๊ฒฐ๋ ํด๋ผ์ด์ธํธ ๋ชฉ๋ก ์ ์ฅ
- clients๋ ํ์ฌ ์ฐ๊ฒฐ๋ WebSocket ํด๋ผ์ด์ธํธ๋ฅผ ์ ์ฅํ๋ Set์ ๋๋ค.
- CORS ์ค์ ์ ํ๋ก ํธ์๋ (Next.js)์์ ์ด ์๋ฒ์ ์์ ๋กญ๊ฒ ์ฐ๊ฒฐํ๊ธฐ ์ํจ์ ๋๋ค.
2๏ธโฃ WebSocket ์ฐ๊ฒฐ ๋ฐ ๋ฉ์์ง ์ฒ๋ฆฌ
wss.on("connection", (ws) => {
console.log("๐ New client connected");
clients.add(ws);
ws.on("message", (message) => {
console.log("๐ฉ Received:", message.toString());
// ๋ชจ๋ ํด๋ผ์ด์ธํธ์๊ฒ ๋ธ๋ก๋์บ์คํธ
for (const client of clients) {
if (client.readyState === WebSocket.OPEN) {
client.send(message.toString());
}
}
});
ws.on("close", () => {
console.log("โ Client disconnected");
clients.delete(ws);
});
});
- wss๋ new WebSocket.Server({ server })๋ก ์์ฑ๋ WebSocket ์๋ฒ ์ธ์คํด์ค์ ๋๋ค.
- wss.on("connection", (ws) => {...}): ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ๋ ๋ ์คํ๋ฉ๋๋ค.
- ws๋ ์ฐ๊ฒฐ๋ ๊ฐ๋ณ ํด๋ผ์ด์ธํธ WebSocket ๊ฐ์ฒด์ ๋๋ค.
- ์๋ก์ด ํด๋ผ์ด์ธํธ๊ฐ ์ ์ํ๋ฉด .on("connection") ์ด๋ฒคํธ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ์ฐ๊ฒฐ๋ ws ์ธ์คํด์ค๋ฅผ clients Set์ ์ ์ฅํ์ฌ ๊ด๋ฆฌํฉ๋๋ค.
ws.on("message", (message) => {
console.log("๐ฉ Received:", message.toString());
...
});
- ํด๋ผ์ด์ธํธ๊ฐ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ฉด, ๋ค๋ฅธ ๋ชจ๋ ํด๋ผ์ด์ธํธ์๊ฒ ๊ทธ๋๋ก ์ ๋ฌํฉ๋๋ค.
- ํ์ฌ ์ ์ ์ค์ธ ๋ชจ๋ ํด๋ผ์ด์ธํธ๋ฅผ ์ํํ๋ฉด์ readyState๊ฐ OPEN์ธ ๊ฒฝ์ฐ์๋ง ๋ฉ์์ง๋ฅผ ์ ์กํฉ๋๋ค.
- ์ฆ, ํด๋ผ์ด์ธํธ A๊ฐ ๋ณด๋ธ ๋ฉ์์ง๋ฅผ ์๋ฒ๊ฐ ๋ฐ์์ B, C, D ๋ฑ ๋ชจ๋ ํด๋ผ์ด์ธํธ์๊ฒ ๋์ผํ๊ฒ ์ ๋ฌํฉ๋๋ค.
for (const client of clients) {
if (client.readyState === WebSocket.OPEN) {
client.send(message.toString());
}
}
- ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ ํด์ ๋๋ฉด Set์์ ์ ๊ฑฐํฉ๋๋ค.
ws.on("close", () => {
console.log("โ Client disconnected");
clients.delete(ws);
});
3๏ธโฃ ์๋ฒ ์คํ
const PORT = process.env.PORT || 8080;
server.listen(PORT, () => {
console.log(`๐ WebSocket server running on http://localhost:${PORT}`);
});
- ํด๋ผ์ด์ธํธ๊ฐ ๋ธ๋ผ์ฐ์ ๋ฅผ ๋ซ๊ฑฐ๋ ์ฐ๊ฒฐ์ด ๋๊ธฐ๋ฉด .on("close")๊ฐ ์คํ๋ฉ๋๋ค.
- ์๋ฒ์์๋ ํด๋น WebSocket ๊ฐ์ฒด๋ฅผ clients Set์์ ์ ๊ฑฐํฉ๋๋ค.
- ๋ถํ์ํ ๋ฉ๋ชจ๋ฆฌ ์ ์ ๋ ์ ์ก ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํ ํด๋ฆฐ์ ์์ ์ ๋๋ค.
์ ์ฒด์ฝ๋
const express = require("express");Add commentMore actions
const http = require("http");
const WebSocket = require("ws");
const cors = require("cors");
const app = express();
app.use(cors());
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
const clients = new Set();
wss.on("connection", (ws) => {
console.log("๐ New client connected");
clients.add(ws);
ws.on("message", (message) => {
console.log("๐ฉ Received:", message.toString());
// ๋ธ๋ก๋์บ์คํธ
for (const client of clients) {
if (client.readyState === WebSocket.OPEN) {
client.send(message.toString());
}
}
});
ws.on("close", () => {
console.log("โ Client disconnected");
clients.delete(ws);
});
});
const PORT = process.env.PORT || 8080;
server.listen(PORT, () => {
console.log(๐ WebSocket server running on http://localhost:${PORT});
});
๊ธฐ์ด ์น ์์ผ ์๋ฒ๋ฅผ ์ธํ ํ ๋ค์, ์ค์๊ฐ์ผ๋ก ์ ์ํ ์ฌ์ฉ์๋ฅผ ๊ฐ์งํ๊ณ , ํด๋น ์ ์ ์ ํ๋กํ ์ฌ์ง์ผ๋ก ์๋ฐํ๋ฅผ ๋์ฐ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ฒ ์ต๋๋ค.
GitHub - Ureka-Middle-Team1/nearby-wss-server: ๊ทผ๊ฑฐ๋ฆฌ ์์น ๊ธฐ๋ฐ ์ค์๊ฐ ํต์ ์ ์ํ ์๋ฒ ๋ ํฌ
๊ทผ๊ฑฐ๋ฆฌ ์์น ๊ธฐ๋ฐ ์ค์๊ฐ ํต์ ์ ์ํ ์๋ฒ ๋ ํฌ. Contribute to Ureka-Middle-Team1/nearby-wss-server development by creating an account on GitHub.
github.com
