웹 소켓으로 실시간 데이터 전송하기

WS 모듈 사용하기

필요한 것들을 아래와 같이 설치해준다.

 

D:\code\node\gifchat>npm i cookie-parser dotenv express express-session morgan nunjucks && npm -i D nodemon

added 82 packages, and audited 83 packages in 5s

14 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Unknown command: "D"

To see a list of supported npm commands, run:
  npm help

 

이번에 사용할 ws 도 추가로 설치해준다.

D:\code\node\gifchat>npm i ws

added 1 package, and audited 84 packages in 1s

14 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

웹소켓에는 네 가지 상태가 있다. CONNECTING(연결 중), OPEN(열림), CLOSING(닫는 중), CLOSED(당힘) 이다. OPEN일 때만 에러 없이 메세지를 보낼 수 있다.

보낼 때는 ws.send 로 보내고 받을 때는 ws.on 으로 받는다.

//socket.js 파일

const WebSocket = require("ws");

module.exports = (server) => {
  const wss = new WebSocket.Server({ server });

  wss.on("connection", (ws, req) => {
    // 웹소켓 연결 시
    const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
    console.log("새로운 클라이언트 접속", ip);
    ws.on("message", (message) => {
      // 클라이언트로부터 메시지
      console.log(message.toString());
    });
    ws.on("error", (error) => {
      // 에러 시
      console.error(error);
    });
    ws.on("close", () => {
      // 연결 종료 시
      console.log("클라이언트 접속 해제", ip);
      clearInterval(ws.interval);
    });

    ws.interval = setInterval(() => {
      // 3초마다 클라이언트로 메시지 전송
      if (ws.readyState === ws.OPEN) {
        ws.send("서버에서 클라이언트로 메시지를 보냅니다.");
      }
    }, 3000);
  });
};

 

서버를 실행하면 아래와 같이 서버에서 클라이언트로 메세지를 보내는 것 확인 가능

 

 

서버에서도 확인 가능

 

 

Socket.IO 모듈 사용하기

socket.io에서는 키와 값으로 보낸다.

emit(’키’,’값’)

socket.io는 http로 연결을 한다.

socket.io는 polling 과 websocket 을 둘 다 지원한다.websocket으로만 사용하도록 설정할 수도 있다.

socket.js 와 index.html을 변경하면 아래와 같이 확인이 가능하다.

 

//socket.js

const SocketIO = require("socket.io");

module.exports = (server) => {
  const io = SocketIO(server, { path: "/socket.io" });

  io.on("connection", (socket) => {
    // 웹소켓 연결 시
    const req = socket.request;
    const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
    console.log("새로운 클라이언트 접속!", ip, socket.id, req.ip);
    socket.on("disconnect", () => {
      // 연결 종료 시
      console.log("클라이언트 접속 해제", ip, socket.id);
      clearInterval(socket.interval);
    });
    socket.on("error", (error) => {
      // 에러 시
      console.error(error);
    });
    socket.on("reply", (data) => {
      // 클라이언트로부터 메시지
      console.log(data);
    });
    socket.interval = setInterval(() => {
      // 3초마다 클라이언트로 메시지 전송
      socket.emit("news", "Hello Socket.IO");
    }, 3000);
  });
};


// index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>GIF 채팅방</title>
  </head>
  <body>
    <div>F12를 눌러 console 탭과 network 탭을 확인하세요.</div>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io.connect("http://localhost:8005", {
        path: "/socket.io",
        transports: ["websocket"],
      });
      socket.on("news", function (data) {
        console.log(data);
        socket.emit("reply", "Hello Node.JS");
      });
    </script>
  </body>
</html>

 

실시간 채팅방 만들기

몽고디비를 사용한다. 필요한 파일들을 아래과 같이 설치한다.

 

D:\code\node\gifchat>npm i mongoose multer color-hash@2

added 39 packages, and audited 167 packages in 9s

 

몽고디비를 사용해야 하기 때문에 실행시켜준다.

PS C:\Program Files\MongoDB\Server\7.0\bin> ./mongod --ipv6

 

서버를 시작해서 몽고디비까지 접속이 잘 되는 것을 확인다.

D:\code\node\gifchat>npm start

> gif-chat@0.0.1 start
> nodemon app

[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node app.js`
(node:4060) [MONGODB DRIVER] Warning: useNewUrlParser is a deprecated option: useNewUrlParser has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version
(Use `node --trace-warnings ...` to show where the warning was created)
8005 번 포트에서 대기중
몽고디비 연결 성공

 

에러 없이 서버가 잘 실행되면 아래와 같이 2개의 웹브라우저에서 접속해본다.

서버에서도 2개의 세션이 붙은 것을 확인할 수 있다.

 

#c587b0 J5RByMDgnkNN_nux7zrvG6EGaEi0d-QJ
Mongoose: rooms.find({}, {})
GET / 304 27.828 ms - -
room 네임스페이스 접속 해제
GET /main.css 304 1.593 ms - -
room 네임스페이스에 접속
Mongoose: rooms.find({}, {})
GET / 304 4.459 ms - -
room 네임스페이스 접속 해제
GET /main.css 304 1.506 ms - -
room 네임스페이스에 접속
room 네임스페이스 접속 해제
chat 네임스페이스에 접속
#76862d 6t7e0goBwVLrd4Ny2Ok5g6FDYK-5Cmsj
GET /room 200 3.556 ms - 806

 

방을 생성하면 다른 세션에서 실시간으로 방이 생성된 것을 확인할 수 있고 방 입장도 가능하다.

 

입장하거나 퇴장하는 메세지도 잘 출력 되는지 확인한다.

 

메세지도 양쪽에서 잘 출력 되는지 확인한다.

 

최종적으로 gif 파일 올리기 까지 정상적으로 올라가는 것을 확인할 수 있다.

'Javascript > Node' 카테고리의 다른 글

노드 교과서 섹션 8  (0) 2023.08.23
노드 교과서 섹션 9  (0) 2023.08.22
노드 교과서 섹션 10  (0) 2023.08.19
노드 교과서 섹션 12  (0) 2023.08.17
노드 교과서 섹션 13  (0) 2023.08.09

실시간 경매 시스템 만들기(서버센트이벤트, 스케줄링)

DB는 mysql을 사용한다. 필요한 것들을 설치해준다.

 

D:\code\node\auction>npm i cookie-parser dotenv express express-session morgan multer nunjucks

added 101 packages, and audited 102 packages in 16s

15 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

D:\code\node\auction>npm i -D nodemon

added 29 packages, and audited 131 packages in 18s

19 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

D:\code\node\auction>npm i sequelize sequelize-cli mysql2

added 128 packages, and audited 259 packages in 40s

38 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

D:\code\node\auction>npx sequelize init

Sequelize CLI [Node: 20.16.0, CLI: 6.6.2, ORM: 6.37.3]

Created "config\config.json"
Successfully created models folder at "D:\code\node\auction\models".
Successfully created migrations folder at "D:\code\node\auction\migrations".
Successfully created seeders folder at "D:\code\node\auction\seeders".

 

필요한 모델들을 작성해주고 db:create 를 수행한다.

auction.js, good.js, user.js 파일 생성 후 작성한다.

D:\code\node\auction>npx sequelize db:create

Sequelize CLI [Node: 20.16.0, CLI: 6.6.2, ORM: 6.37.3]

Loaded configuration file "config\config.json".
Using environment "development".
Database nodeauction created.

 

로그인 기능을 위해 passport, bcrypt도 같이 설치

 

D:\code\node\auction>npm i passport passport-local bcrypt  
npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way
to coalesce async requests by a key value, which is much more comprehensive and powerful.
npm warn deprecated npmlog@5.0.1: This package is no longer supported.
npm warn deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated are-we-there-yet@2.0.0: This package is no longer supported.
npm warn deprecated gauge@3.0.2: This package is no longer supported.

added 58 packages, and audited 317 packages in 26s

42 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

회원가입, 로그인, 경매 시스템에 대해서 작성한 후에 회원가입을 해본 화면이다.

아래는 최초 메인화면

회원 가입 화면

 

회원 가입 후 로그인 화면

 

상품 등록 화면

 

 

서버센트 이벤트 사용하기

 처음에 클라이언트가 서버와 연결을 한 번 맺으면 이제 HTTP에서는 클라이언트 요청을 서버로부터 응답을 받을 수가 있는데 웹소켓이나 서버센트 이벤트는 서버가 먼저 데이터를 클라이언트로 내려 보내줄 수가 있다.

 

 그런데 웹소켓과 서버센트 이벤트가 다른 점은 웹소켓은 양방향으로 클라이언트에서 서버로 서버에서 클라이언트로 서로 왔다 갔다 할 수 있는데 서버센트 이벤트는 서버에서 클라이언트로만 일방향으로 데이터를 보내줄 수 있다.

 

예를 들어 서버에서 클라이언트로 보내는 알림이나 서버 시간이 필요할 때 서버센트 이벤트를 쓰면 된다.

경매서비스도 서버시간 기준으로 판단을 할 것이다.

 

서버센트 이벤트는 sse 이다. 웹소켓도 쓰기 때문에 같이 설치해준다.

 

D:\code\node\auction>npm i sse socket.io

added 21 packages, and audited 338 packages in 9s

42 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

경매시간을 서버시간 기준으로 받아와서 아래와 같이 표시를 해준다.

서버 시간을 서버 센터 이벤트로 받아와서 갱신이 된다.

 

개발자도구 network 탭에서 확인하면 매초 서버시간을 받는 것을 확인할 수 있다.

 

경매 입찰 관련 코드를 작성하고 2개의 아이디로 로그인 한 다음에 입찰을 진행해본다.

 

2개 아이디 모두 방에 입장한 화면이다.

 

 

나이스데이 계정으로 2000원으로 입찰하면 양쪽 화면에 다 출력된다.

굿데이 계정으로 500원으로 입찰하니 경고가 발생하고 입찰되지 않는다.

 

 

1500원으로 입찰하였을 경우도 경고 팝업이 발생한다.

 

 

아래와 같이 기존 금액보다 높으면 정상적으로 입찰이 진행된다.

 

스케줄링 구현하기

노드에서 정해진 시간 후에 낙찰받을 수 있게 하는 기능을 구현.

node-schedule을 설치한다.

D:\code\node\auction>npm i node-schedule

added 5 packages, and audited 343 packages in 2s

42 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

node-schedule 단점은 서버가 재시작 되었을 경우 전부 사라진다.

 

그렇기 때문에 다시 등록할 수 있는 코드가 작성해주어야 한다. (checkAuction.js 에 작성한다.)

 

경매 프로그램처럼 금액과 관련된 중요한 서비스일 경우 경매 낙찰은 성공하고 돈은 안 빠져 나가는 현상이 생기면 안되기 때문에 transaction을 적용해주어야 한다.

const t = await sequelize.transaction();

...
transaction : t,
...
await t.commit();
...
await t.rollback();
...

 

낙찰 내역이 정상적으로 나타나고 보유 자산도 경매 금액까지 빠졌는지 확인이 가능하다.

 

node-schedule 패키지로 등록한 스케줄은 노드 서버가 종료될 때 같이 종료 되기 때문에 운영체제의 스케줄러를 사용하는 것이 좋다.

 

윈도우에서는 schtasks가 대표적이고, 맥과 리눅스에서는 cron이 대표적이다.

노드에서는 이 두 프로그램의 명령어를 child_process를 통해 호출할 수 있다.

 

'Javascript > Node' 카테고리의 다른 글

노드 교과서 섹션 8  (0) 2023.08.23
노드 교과서 섹션 9  (0) 2023.08.22
노드 교과서 섹션 10  (0) 2023.08.19
노드 교과서 섹션 11  (0) 2023.08.18
노드 교과서 섹션 13  (0) 2023.08.09

CLI 프로그램 만들기

index.js 파일 제일 위에 #!/usr/bin/env node 를 적어 준다.

윈도우에서는 아무 역할이 없지만 리눅스나 맥에서는 이 파일을 노드로 실행하라는 역할을 한다.

 

#!/usr/bin/env node
console.log("hello cli");

 

package.json 파일에 bin 부분을 추가한다.

cli를 실행하면 index.js가 실행된다.

 

{
    "name": "node-cli",
    "version": "0.0.1",
    "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "description": "",
    "bin": {
      "cli": "./index.js"
    }
  }

 

아래처럼 글로벌로 설치하면 index.js 가 프로그램을 설치가 된 것이다.

D:\code\node\cli>npm i -g

added 1 package in 1s

 

실행을 하면 console가 실행되는 것을 확인할 수 있다.

D:\code\node\cli>npx cli
hello cli

 

아래와 같이 코드를 수정했어도 다시 설치할 필요 없이 정상적으로 실행이 된다.

//index.js 파일

#!/usr/bin/env node
console.log("hello cli", process.argv);

 

D:\code\node\cli>npx cli
hello cli [
  'C:\\Program Files\\nodejs\\node.exe',
  'C:\\Users\\john\\AppData\\Local\\npm-cache\\_npx\\bc67c92c0f4afb79\\node_modules\\node-cli\\index.js'
]

 

process.argv 는 매개변수를 불러올 수 있다.

 

D:\code\node\cli>npx cli one two three four
hello cli [
  'C:\\Program Files\\nodejs\\node.exe',
  'C:\\Users\\john\\AppData\\Local\\npm-cache\\_npx\\bc67c92c0f4afb79\\node_modules\\node-cli\\index.js',
  'one',
  'two',
  'three',
  'four'
]

 

터미널에서 사용자의 답변을 듣는 코드를 작성하고 실행 화면이다.

// index.js 파일

#!/usr/bin/env node
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin, // 터미널 인풋
  output: process.stdout, // 터미널 아웃풋
});

rl.question("예제가 재밌나요?(y/n)", (answer) => {
  if (answer === "y") {
    console.log("감사합니다.");
  } else if (answer === "n") {
    console.log("죄송합니다.");
  } else {
    console.log("y 또는 n 만 입력하세요.");
  }
  rl.close();
});

 

D:\code\node\cli>npx cli                        
예제가 재밌나요?(y/n)b
y 또는 n 입력하세요.

D:\code\node\cli>npx cli
예제가 재밌나요?(y/n)y
감사합니다.

D:\code\node\cli>npx cli
예제가 재밌나요?(y/n)n
죄송합니다.

 

아래와 같이 package.json 이 수정되면 다시 설치를 해줘야 한다.

cli : 이 부분이 index.js → template.js 로 변경

 

{
    "name": "node-cli",
    "version": "0.0.1",
    "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "description": "",
    "bin": {
      "cli": "./template.js"
    }
  }
 

 

D:\code\node\cli>npm i -g

up to date in 831ms

 

template를 자동으로 만들어 주는 cli 프로그램을 수행한 결과 화면

자동으로 html 파일을 만들고 안에 내용을 채워진 것을 확인

 

 

설치한 npx cli를 지울 때는 아래 명령어 사용 가능

 

D:\code\node\cli>npm rm -g node-cli

Commander, Inquirer 사용하기

자주 쓰이는 패키지 2개를 알아보자.

버전에 따라서 명령어가 달라질 수 있어서 버전까지 지정해서 설치

D:\code\node\cli>npm i commander@9 inquirer@8

added 53 packages, and audited 54 packages in 7s

15 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

command.js 만들고 package.json 수정 필요, 다시 설치

// package.json 파일
"bin": {
    "cli": "./command.js"
  },

 

// 다시 설치
D:\code\node\cli>npm i -g

up to date in 964ms

 

필수값 , 선택값 구분

program
  .command("template <type>") // <type> 은 필수값, [type] 은 선택 값

 

버전 확인

D:\code\node\cli>npx cli -v
0.0.1

 

설명내용을 확인 가능

D:\code\node\cli>npx cli -h
Usage: cli [options] [command]

Options:
  -v, --version                   output the version number
  -h, --help                      display help for command

Commands:
  template|tmpl [options] <type>  템플릿을 생성합니다.
 
 

 

명령어를 실행하면 아래와 같이 템플릿이 포함된 파일을 자동으로 만들어 준다.

 

아래는 inquirer 버전 URL 이다.

https://www.npmjs.com/package/inquirer?activeTab=versions

 

npx cli 로 실행하고 선택할 때는 화살표로 움직일 수 있다.

D:\code\node\cli>npx cli
? 템플릿 종류를 선택하세요. html    
? 파일의 이름을 입력하세요. new
? 파일이 위치할 폴더의 경로를 입력하세요. public/html
? 생성하시겠습니까? Yes    
이미 해당 파일이 존재합니다
터미널을 종료합니다.

 

조금 더 꾸며볼 수 있다.

chalk 를 설치하면 색깔을 입힐 수 있게 해준다.

 

D:\code\node\cli>npm i chalk@4

up to date, audited 54 packages in 1s

15 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

에러 내용 같은 경우에 아래와 같이 빨간색 볼드체로 보이게 할 수 있다.

console.error(chalk.bold.red("이미 해당 파일이 존재합니다"));

 

성공은 아래와 같이 초록색으로 보이게 할 수 있다.

console.log(chalk.green(pathToFile, "생성 완료"));

 

아래는 색상이 변경된 결과 화면이다.

 

'Javascript > Node' 카테고리의 다른 글

노드 교과서 섹션 8  (0) 2023.08.23
노드 교과서 섹션 9  (0) 2023.08.22
노드 교과서 섹션 10  (0) 2023.08.19
노드 교과서 섹션 11  (0) 2023.08.18
노드 교과서 섹션 12  (0) 2023.08.17

+ Recent posts