>웹 프론트엔드 >JS 튜토리얼 >Socket.io 및 Redis를 사용하여 채팅 애플리케이션을 구축하고 배포합니다.

Socket.io 및 Redis를 사용하여 채팅 애플리케이션을 구축하고 배포합니다.

王林
王林원래의
2024-08-26 21:40:32538검색

Build and deploy a chat application using Socket.io and Redis.

이 튜토리얼에서는 웹 소켓을 사용하여 채팅 애플리케이션을 구축해 보겠습니다. 웹 소켓은 실시간 데이터 전송이 필요한 애플리케이션을 구축하려는 경우 정말 유용합니다.

이 튜토리얼이 끝나면 자체 소켓 서버를 설정하고, 실시간으로 메시지를 보내고 받고, Redis에 데이터를 저장하고, 렌더링 및 Google Cloud Run에 애플리케이션을 배포할 수 있게 됩니다.

우리는 무엇을 만들 것인가?

채팅 애플리케이션을 구축할 예정입니다. 간략하게 설명하기 위해 서버만 설정하겠습니다. 자신만의 프런트엔드 프레임워크를 사용하여 따라할 수 있습니다.

이 채팅 애플리케이션에는 방이 있으며 사용자는 방에 참여하여 채팅을 시작할 수 있습니다. 모든 것을 단순하게 유지하기 위해 사용자 이름이 고유하지 않다고 가정합니다. 그러나 각 방에는 특정 사용자 이름을 가진 사용자가 한 명만 있을 수 있습니다.

소켓 서버를 설정합니다.

먼저 필수 종속성을 설치해야 합니다.

npm i express cors socket.io -D @types/node

우리는 소켓 서버를 설정하기 위해 http 모듈을 사용할 것입니다. 우리 앱이 터미널에서 실행될 것이기 때문에 모든 출처를 허용해야 합니다.

import express from "express";
import cors from "cors"
import { Server } from "socket.io";
import { createServer } from "http"

const app = express();
const server = createServer(app);

// create a socket server.
const io = new Server(server, {
  cors: {
    origin: "*",
    credentials: true,
  }
});

// listen to connections errors
io.engine.on("connection_error", console.log)

app.use(cors())

const PORT = 3000;
server.listen(PORT, () => console.log(`Server running on port ${PORT}`));

Redis를 설정합니다.

우리는 Redis를 사용하여 회의실 및 사용자 정보와 함께 메시지를 저장할 것입니다. upstash redis(무료)를 사용할 수 있습니다. Upstash 대시보드에서 새 Redis 인스턴스를 생성합니다. 생성 후에는 Redis 인스턴스에 연결하는 데 사용할 수 있는 redis URL을 받게 됩니다.

원하는 Redis 클라이언트를 설치하세요. 저는 ioredis를 사용할 예정입니다.

npm i ioredis

다음으로 Redis 클라이언트를 초기화하고 얻은 연결 URL을 사용하여 Redis 서버에 연결하겠습니다.

/** /src/index.ts */
import { Redis } from "ioredis"

if (!process.env.REDIS_URL) throw new Error("REDIS_URL env variable is not set");
const redis = new Redis(process.env.REDIS_URL);

// listen to connection events.
redis.on("connect", () => console.log("Redis connected"))
redis.on("error", console.log)

이벤트를 처리합니다.

사용자는 방을 만들거나 기존 방에 참여할 수 있습니다. 객실은 고유한 객실 ID로 식별됩니다. 각 회원은 전체가 아닌 방 내에서 고유한 사용자 이름을 갖습니다.

Redis 세트에 룸 ID를 저장하여 서버의 모든 활성 룸을 추적할 수 있습니다.

우리의 목적에 따라 사용자 이름은 방 내에서만 고유합니다. 그래서 우리는 방 ID와 함께 세트에 저장합니다. 이렇게 하면 룸 ID와 회원 ID의 조합이 전 세계적으로 고유하게 됩니다.

방 생성을 위한 소켓 이벤트를 설정할 수 있습니다. 방을 생성할 때 생성을 요청한 회원도 방에 추가합니다.

io.on("connection", () => {
    // ...
    socket.on("create:room", async (message) => {
        console.log("create:room", message)

        const doesRoomExist = await redis.sismember("rooms", message.roomId)
        if (doesRoomExist === 1) return socket.emit("error", { message: "Room already exist."})

        const roomStatus = await redis.sadd("rooms", message.roomId)
        const memStatus = await redis.sadd("members", message.roomId + "::" + message.username)

        if (roomStatus === 0 || memStatus === 0) return socket.emit("error", { message: "Room creation failed." })

        socket.join(message.roomId)
        io.sockets.in(message.roomId).emit("create:room:success", message)
        io.sockets.in(message.roomId).emit("add:member:success", message)
  })
}

기존 방에 새 구성원을 추가하려면 먼저 해당 방에 해당 구성원이 이미 존재하는지 확인해야 합니다.

io.on("connection", () => {
    // ...
    socket.on("add:member", async (message) => {
        console.log("add:member", message)

        const doesRoomExist = await redis.sismember("rooms", message.roomId)
        if (doesRoomExist === 0) return socket.emit("error", { message: "Room does not exist." })

        const doesMemExist = await redis.sismember("members", message.roomId + "::" + message.username)
        if (doesMemExist === 1) return socket.emit("error", { message: "Username already exists, please choose another username." })

        const memStatus = await redis.sadd("members", message.roomId + "::" + message.username)
        if (memStatus === 0) return socket.emit("error", { message: "User creation failed." })

        socket.join(message.roomId)
        io.sockets.in(message.roomId).emit("add:member:success", message)
  })

    socket.on("remove:member", async (message) => {
        console.log("remove:member", message)

        const doesRoomExist = await redis.sismember("rooms", message.roomId)
        if (doesRoomExist === 0) return socket.emit("error", { message: "Room does not exist." })

        await redis.srem("members", message.roomId + "::" + message.username)

        socket.leave(message.roomId)
        io.sockets.in(message.roomId).emit("remove:member:success", message)
      })
}

마지막으로 채팅 이벤트를 생성합니다.

io.on("connection", () => {
    socket.on("create:chat", (message) => {
    console.log("create:chat", message)
    redis.lpush("chat::" + message.roomId, message.username + "::" + message.message)
    io.sockets.in(message.roomId).emit("create:chat:success", message)
  })
}

전개.

소켓 서버에는 지속적인 연결이 필요하며 서버리스 환경에서는 작동하지 않습니다. 따라서 vercel에서는 소켓 서버를 배포할 수 없습니다.

Render, fly.io, Google Cloud Run 등 다양한 위치에 배포할 수 있습니다.

세우다

렌더링 시 배포가 간단합니다. dockerfile이 있으면 해당 dockerfile에서 프로젝트를 자동으로 빌드합니다. Render에는 무료 등급이 있지만 무료 등급에서는 콜드 스타트가 가능하다는 점을 명심하세요.

여기 내 dockerfile이 있습니다.

# syntax=docker/dockerfile:1
ARG NODE_VERSION=20.13.1
ARG PNPM_VERSION=9.4.0

FROM node:${NODE_VERSION}-bookworm AS base

## set shell to bash
SHELL [ "/usr/bin/bash", "-c" ]
WORKDIR /usr/src/app

## install pnpm.
RUN --mount=type=cache,target=/root/.npm \
    npm install -g pnpm@${PNPM_VERSION}

# ------------
FROM base AS deps
# Download dependencies as a separate step to take advantage of Docker's caching.
# Leverage a cache mount to /root/.local/share/pnpm/store to speed up subsequent builds.
# Leverage bind mounts to package.json and pnpm-lock.yaml to avoid having to copy them
# into this layer.
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
    --mount=type=cache,target=/root/.local/share/pnpm/store \
    pnpm install --prod --frozen-lockfile

# -----------
FROM deps AS build
## downloading dev dependencies.
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
    --mount=type=cache,target=/root/.local/share/pnpm/store \
    pnpm install --frozen-lockfile

COPY . .
RUN pnpm run build

# -------------
FROM base AS final
ENV NODE_ENV=production
USER node
COPY package.json .

# Copy the production dependencies from the deps stage and also
# the built application from the build stage into the image.
COPY --from=deps /usr/src/app/node_modules ./node_modules
COPY --from=build /usr/src/app/dist ./dist

EXPOSE 3000
ENTRYPOINT [ "pnpm" ]
CMD ["run", "start"]

구글 클라우드 런

콜드 스타트를 방지하고 렌더링할 수 있는 무료 대안을 원한다면 Google Cloud Run을 사용해야 합니다. Cloud Run에 배포하는 단계는 이 문서의 범위를 벗어나지만 수행해야 할 작업의 간단한 목록은 다음과 같습니다.

  1. 아래 제공된 dockerfile에서 docker 이미지를 빌드하세요.

  2. Google Artifact Registry 서비스를 사용하여 아티팩트 저장소를 만듭니다.

  3. Docker 이미지 이름을 -docker.pkg.dev//:

    형식으로 바꿉니다.
  4. 이미지를 유물 저장소에 푸시하세요.

  5. Google Cloud Run에 이미지를 배포합니다. 콜드 스타트를 방지하려면 최소 활성 인스턴스를 1로 설정하세요.

이번 튜토리얼은 여기까지입니다.

읽어주셔서 감사합니다 ❣️

위 내용은 Socket.io 및 Redis를 사용하여 채팅 애플리케이션을 구축하고 배포합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.