미새문지

웹 소켓(Web Socket) 채팅 앱 만들기 - 클라이언트 서버 연결 본문

웹 프론트엔드

웹 소켓(Web Socket) 채팅 앱 만들기 - 클라이언트 서버 연결

문미새 2024. 4. 27. 23:30
728x90

유튜브의 코딩알려주는누나 영상에서 채팅앱을 만드는 강의를 듣고 작성한다.

코딩알려주는누나 강의 영상: https://www.youtube.com/watch?v=uE9Ncr6qInQ

 

다음 게시글 :

https://moonmisae-cdpt.tistory.com/211

 

웹 소켓(Web Socket) 채팅 앱 만들기 - 유저 로그인

코딩알려주는누나 웹소켓 강의 : https://www.youtube.com/watch?v=oFiw5VvgRFg&t=0s 이전 학습 내용:https://moonmisae-cdpt.tistory.com/209 웹 소켓(Web Socket) 채팅 앱 만들기 - 클라이언트 서버 연결유튜브의 코딩알려

moonmisae-cdpt.tistory.com


웹 소켓(WebSocket)

웹 상에서 양방향 통신을 가능하게 하는 기술. 이 기술은 웹 브라우저와 서버 간에 실시간으로 데이터를 주고받을 수 있게 해주며, 웹 소켓은 HTTP 프로토콜을 사용하여 초기 연결을 설정한 후, 연결이 성립되면 양쪽 모두에서 데이터를 자유롭게 전송할 수 있는 지속적인 연결을 제공한다.

 

웹 소켓은 특히 실시간 애플리케이션에 유용한데, 예를 들어, 채팅 애플리케이션, 실시간 게임, 실시간으로 업데이트 되는 스포츠 점수판 등에서 매우 유용하게 사용된다.

이전의 HTTP 폴링 방식에 비해 서버와 클라이언트 간의 데이터 전송이 훨씬 효율적이고 빠르기 때문에, 사용자 경험을 크게 향상시킬 수 있다.

 

작동 과정

  1. 클라이언트(웹 브라우저)가 웹 서버에 웹 소켓 연결을 요청한다. 이 때 HTTP 요청을 사용하며, 이 요청을 업그레이드(Upgrade) 헤더를 포함하여 웹 소켓 연결로 전환하겠다는 의도를 서버에 전달한다.
  2. 서버가 이 요청을 수락하면, HTTP 연결을 웹 소켓 연결로 업그레이드하는데, 이 후부터는 양방향 통신이 가능해진다.
  3. 연결이 열려 있는 동안, 클라이언트와 서버는 서로에게 메시지를 자유롭게 보낼 수 있다.
  4. 어느 한 쪽이든 연결을 종료할 수 있다.

웹 소켓의 주요 장점은 실시간 통신이 가능하다는 것과, 일단 연결이 설정되면 추가적인 HTTP 요청 없이도 양방향으로 데이터를 교환할 수 있다는 점이기 때문에, 이로 인해 네트워크 지연 시간이 줄어들고, 애플리케이션의 성능이 개선된다.


웹 소켓을 통신하기 위해 클라이언트와 서버 둘다 필요한데, 먼저 서버 먼저 생성해보자

npm init

서버 폴더를 만들고 그 안에서 npm init을 해줌으로써 package.json을 생성했다.

 

이 후, express와 mongoose, cors dotenv http를 설치해줬다.

npm i express, mongoose, cors dotenv http

express는 서버를 만들 수 있게 도와주는 라이브러리이다.

mongoose는 mongoDB를 쉽게 사용할 수 있게 도와주는 라이브러리이다.

cors는 프론트와 백엔드가 서로 통신할 수 있게 도와주는 라이브러리이다.

dotenv는 설치한 환경변수를 가져올 수 있는 라이브러리이다.

http는 http 서버를 만들 수 있게 해주는 라이브러리이다.

 

설치가 끝나면 메인 라이브러리인 socket.io를 설치한다.

socket.io

소켓을 구현해서 받을 정보는 유저정보와, 메세지 정보이다.

 

이제 스키마를 만들어야 한다.

models라는 폴더를 만들고 그 안에 user.js를 만든다.

const mongoose = require("mongoose");

const userSchema = new mongoose.Schema({
    name: {
        type: String,
        required: [true, "User must type name"],
        unique: true,
    },
    token: {
        type: String,
    },
    online: {
        type: Boolean,
        default: false,
    },
});
module.exports = mongoose.model("User", userSchema);

이 코드는 유저스키마이며 유저의 정보를 어떻게 받아야 하는지 설명하는 코드이다.

현재 코드에서 받을 값은 유저 이름과, 유저의 연결 id 정보를 저장할 token, online은 강의 말로는 지금은 필요없다곤 하는데 이 후 유저가 온라인인지 오프라인인지 판단하기 위한 코드를 미리 작성해놨다고 한다.

 

그리고 메세지를 담을 정보도 받아야 하기 때문에 chat.js도 만든다.

const mongoose = require("mongoose");

const chatSchema = new mongoose.Schema(
    {
        chat: String,
        user: {
            id: {
                type: mongoose.Schema.ObjectId,
                ref: "User",
            },
            name: String,
        },
    },
    {timestamp: true}
);
module.exports = mongoose.model("Chat", chatSchema);

이 코드는 챗스키마이며 메세지의 정보를 어떻게 받아야 하는지 설명하는 코드이다.

chat은 메세지의 내용을 담고, 메세지를 누가 보냈는지 확인하는 user를 선언해놨다.

 

이제 유저정보와 메세지정보를 어떻게 받을지 지정했으니 서버를 생성해야 한다.

상위 폴더에 app.js를 만든다.

폴더 구조

app.js안에 서버를 만들 코드를 작성한다.

const express = require("express")
const mongoose = require("mongoose")
require('dotenv').config()
const cors = require("cors")
const app = express()

app.use(cors())

mongoose.connect(process.env.DB, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
}).then(()=>console.log("connected to database"));

module.exports = app

먼저 DB를 연결하기 위해 mongoose를 가져와 DB의 localhost 포트번호를 연결한다.

같은 위치에 .env 파일을 생성하고 포트번호와 DB를 작성한다.

DB의 연결 코드 작성이 끝나면 실행을 시켜볼건데, 그 전에 nodemon이라는 라이브러리를 설치해야 한다.

nodemon 설치

nodemon은 파일에 변화가 생기면 자동 리로딩을 해주기 때문에 매번 재시작을 할 필요가 없다.

설치가 끝나면 실행을 시켜본다.

nodemon 실행 모습

DB가 연결되었다는 텍스트가 뜬다. 성공

 

이제 웹 소켓을 세팅하기 위해 index.js를 작성한다.

 

http를 이용해 서버를 만들고 웹 소켓과 DB를 올린다.

// http를 통해 서버 생성
const {createServer} = require("http");
const app = require("./app");
// 웹소켓을 가지고 온다.
const {Server} = require("socket.io");
require("dotenv").config();

// createServer를 이용해 서버 만들기
const httpServer = createServer(app);
// httpServer를 올려 서버를 생성한다.(cors를 이용해 프론트와의 통신 수락)
const io = new Server(httpServer, {
    cors: {
        origin: "http://localhost:3000"
    }
});

// 5001번에 포트를 띄워줌으로써 프론트엔드가 접근할 수 있게
httpServer.listen(process.env.PORT, () => {
    console.log('server listening on port', process.env.PORT);
});

서버를 생성하기 위한 간단한 세팅은 끝났고 저 io를 사용해야 하는데 코드가 길어지기 때문에 다른 파일에서 작성한다.

 

util 폴더를 만들고 io.js를 생성한다.

module.exports = function(io) {
    
}

io에 exports만 붙여서 가져올 수 있게 한 후

 

io.js를 가져와준다.

 

module.exports = function(io) {
    // 클라이언트 연결을 받을 수 있는 on을 사용해 연결되면 메세지 출력
    io.on("connection", async(socket) => {
        console.log("client is connected", socket.id);
    });
};

io.js 코드에 클라이언트 연결을 위해 on을 사용해서 연결되면 메세지를 출력할 수 있게 작성했다.

 

백엔드 작성은 끝났고 이제 프론트엔드를 작성해야 한다.

프론트엔드 폴더는 유튜브 강의의 설명에 프론트엔드 깃 링크가 있어 거기서 다운받으면 된다.

프론트엔드 폴더

프론트엔드에도 소켓을 만들어줘야 한다. 폴더를 외부에서 가져왔기 때문에 package.json에 깔려있는 라이브러리를 설치해야 하는데 터미널로 해당 폴더로 이동해서 npm i 해주면 package 안의 라이브러리들이 전부 설치된다.(node_modules가 설치되야 한다.)

 

src에서 server.js를 생성 후 코드 작성

import {io} from "socket.io-client"

const socket = io("http://localhost:5001")

export default socket;

 

프론트에서 소켓 라이브러리를 이용해 서버 포트인 5001번을 담아 외부에서 사용할 수 있게 작성했다.

 

이 후 app.js에서 방금 작성한 소켓을 import 한다.

 

이렇게 작성을 했으면 이제 프론트엔드와 백엔드의 연결 테스트를 해야 한다.

각 서버를 켜야 한다.

서버는 nodemon index.js로 클라이언트는 npm start로 켜준다.

 

그럼 이 화면이 나오게 되는데 이 창에서 새로고침을 하게 되면 서버 메세지에 클라이언트와 연결됐다는 메세지가 뜨게 된다.

새로고침할때마다 다른 id가 뜨기 때문에 다른 창에서 localhost:3000으로 화면을 실행하게 되면 이전의 id와 다른 id로 된다.

 

클라이언트와 서버의 연결은 확인했으니 이제 연결을 끊어줘야 하는데 서버의 utils/io.js에서 disconnect를 이용해 확인하면 된다.

module.exports = function(io) {
    // 클라이언트 연결을 받을 수 있는 on을 사용해 연결되면 메세지 출력
    io.on("connection", async(socket) => {
        console.log("client is connected", socket.id);

		// 소켓이 disconnect시 메세지 출력
        socket.on("disconnect", () => {
            console.log("user is disconnected");
        });
    }); 
};

 

현재 열려 있는 브라우저를 끄게 되면 자동적으로 서버에서 메세지를 출력해준다.

 

클라이언트와 서버의 소켓을 이용한 연결은 여기까지

728x90