[WebSocket, Socket.io] WebSocket, Socket.io 객체 모두 이용하기

한음·2023년 3월 11일
0
post-thumbnail

** 해당 글은 실시간 webapp 토이프로젝트 진행 중
localtunnel 혹은 ngrok으로 두 개의 포트를 외부에 오픈하고 통신하려다 삽질한 기록으로

실제 서버를 띄웠을 때 WS 포트 문제와는 관련이 없다.
-> 해당 이슈는 더 좋은 글이 있어 링크를 공유한다.

발단

깡통 WS 통신과, Socket.io를 사용했을 때의 차이를 비교하려 했다.

서버 코드

import WebSocket, { MessageEvent } from "ws";
import http from "http";
import express from "express";
import { Server as SocketIO } from "socket.io";
const WS_PORT: number = 3000;
const IO_PORT: number = 3001;

...

const app: express.Application = express();
const path = require("path");
app.use(express.static(path.join(__dirname, "/public/dist")));
app.get("/", (req, res) => res.sendFile(__dirname, "/public/dist/index.html"));


const httpServerForWS = http.createServer(app); // http 서버
const httpServerForIO = http.createServer(app); // http 서버
const wsServer = new WebSocket.Server({ server: httpServerForWS });
wsServer.on("connection", (socket: ISocket, request: http.IncomingMessage) => {
	...
});

const ioServer: SocketIO = new SocketIO(httpServerForIO, {
  cors: {
    origin: ["http://localhost:5173", "http://localhost:3000"],
    methods: ["GET", "POST"],
    credentials: true,
  },
});
	...
});
httpServerForWS.listen(WS_PORT, () =>
  console.log(`Listening on PORT: http://localhost:${WS_PORT}`)
);
httpServerForIO.listen(IO_PORT, () =>
  console.log(`Listening on PORT: http://localhost:${IO_PORT}`)
);

socket.io, 깡통 WS 비교를 위해 서버를 두개 만들어 (httpServerForWS, httpServerForIO)
포트 3000, 3001을 할당했다.

서버, 클라이언트 로컬 dev 환경에서는 당연히 잘됐다.
폰과 pc의 실시간 통신 테스트 진행을 위해 클라이언트 소스를 빌드해 정적으로 제공하고(PORT 3000)
ngrok으로 포트 3000번을 열어줬다.

ngrok, localtunnel 이용해 포트 외부 오픈

ngrok 랜덤 도메인에서 localhost:3001로 요청을 보내니 당연히 CORS 문제가 발생했다.
임시로 socket.io 서버에서 랜덤 도메인에 대한 cors 허용 설정을 추가했지만 다른 문제가 있었다.

외부 접속 문제

pc에서는 어찌저찌 해결했으나
당연히 폰에서는 socket.io localhost 서버로 요청을 보낼수가 없다.

ngrok으로 3001포트도 오픈하고 해당 도메인으로 요청 보내도록 클라이언트 소스 수정하고 다시 빌드해 express 넣어서 시도해볼까 했지만

애초에 localtunnel 이나 ngrok 자체가 테스트용으로 사용한건데 그렇게까지 하기 싫었다.

서버 합체

그냥 두 서버를 합쳐서 해결했다. ㄱ-
동일한 httpServer로 WS 객체와 socket.io 객체를 생성했다.

...

const PORT: number = 3000;
const app: express.Application = express();
const path = require("path");
app.use(express.static(path.join(__dirname, "/public/dist")));
app.get("/", (req, res) => res.sendFile(__dirname, "/public/dist/index.html"));

const httpServer = http.createServer(app); // http 서버
const wsServer = new WebSocket.Server({ server: httpServer }); // ws(websocket)

wsServer.on("connection", (socket: ISocket, request: http.IncomingMessage) => {
	...
});

const ioServer: SocketIO = new SocketIO(httpServer, {
  cors: {
    origin: ["http://localhost:5173", "http://localhost:3000"],
    methods: ["GET", "POST"],
    credentials: true,
  },
});
	...
});
httpServer.listen(PORT, () =>
  console.log(`Listening on PORT: http://localhost:${PORT}`)
);

실제 서버를 띄워서 진행한게 아니라 로컬환경을 외부에 오픈하려고 꾸역꾸역 삽질한거라
딱히 해결했다고 보기는 어렵다.

사실 소스를 분리해 서버 두개를 실제로 띄우고 클라이언트에서 각 서버로 요청을 보냈다면 위 부분은 크게 고민할 게 없다.


클라이언트 소스(참고)

// SocketIOPage.tsx
const socketProtocol = window.location.protocol === "https:" ? "wss" : "ws"; // dev / prod
const isProd = process.env.NODE_ENV === "production";
const socket = io(
  `${socketProtocol}://${window.location.hostname}${isProd ? "" : ":3000"}`,
  {
    withCredentials: true,
  }
);
function SocketIOPage() {
  ...
}
// WSPage.tsx
const socketProtocol = window.location.protocol === "https:" ? "wss" : "ws"; // dev / prod
const isProd = process.env.NODE_ENV === "production";
const socket: WebSocket = new WebSocket(
  `${socketProtocol}://${window.location.hostname}${isProd ? "" : ":3000"}`
);
export function WSPage() {
  ...
}

컴포넌트 외부에서 소켓 연결을 생성한다.
prod 환경과 dev 환경을 구분해 연결 도메인을 설정
(ngrok의 경우 https 로 오픈된다.)

profile
https://github.com/0hhanum

0개의 댓글