[Node.js] socket.io를 이용한 채팅 구현하기

node.js환경에서 socket.io를 이용해서 간단한 채팅 프로그램을 만드는 방법을 공유하겠습니다.

라이브러리 설치

npm init으로 package.json 파일을 만듭니다.

express, socket.io가 필요합니다. npm i express socket.io를 해서 설치해 줍니다.

위처럼 dependencies에 설치한 라이브러리들이 존재하면 됩니다. 설치된 라이브러리는 node_modules 폴더에 있습니다.

chat.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Socket.io Chat Example</title>
    <link
      rel="stylesheet"
      href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
    />
  </head>
  <body>
    <div class="container">
      <h3>Socket.io Chat Example</h3>
      <!-- <form class="form-inline"> -->
      <form class="form-horizontal">
        <div class="form-group">
          <label for="name" class="col-sm-2 control-label">Name</label>
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="name"
              placeholder="Name"
            />
          </div>
        </div>
        <div class="form-group">
          <label for="room" class="col-sm-2 control-label">Room</label>
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="room"
              placeholder="Room"
            />
          </div>
        </div>
        <div class="form-group">
          <label for="to" class="col-sm-2 control-label">To</label>
          <div class="col-sm-10">
            <input type="text" class="form-control" id="to" placeholder="to" />
          </div>
        </div>
        <div class="form-group">
          <label for="msg" class="col-sm-2 control-label">Message</label>
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="msg"
              placeholder="Message"
            />
          </div>
        </div>
        <div class="form-group">
          <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-default">Send</button>
          </div>
        </div>
      </form>
      <ul id="chat"></ul>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      $(function () {
        // 지정 namespace로 접속한다
        var chat = io("http://localhost:4000/chat"),
          news = io("/news");

        $("form").submit(function (e) {
          e.preventDefault();

          // 서버로 자신의 정보를 전송한다.
          chat.emit("chat message", {
            name: $("#name").val(),
            room: $("#room").val(),
            msg: $("#msg").val(),
            to: $("#to").val(),
          });
        });

        // 서버로부터의 메시지가 수신되면
        chat.on("chat message", function (data) {
          console.log(data);
          $("#chat").append($("<li>").text(data.from.name + ": " + data.msg));
        });
      });
    </script>
  </body>
</html>

엔터 혹은 전송 버튼을 클릭하면 name, room, msg, to의 아이디를 가지고 있는 인풋값을 서버로 전송합니다.

그리고 서버에서 오는 데이터는 chat아이디에 추가하는 코드입니다.
 

chat.js

var app = require("express")();
var server = require("http").createServer(app);
// http server를 socket.io server로 upgrade한다
var io = require("socket.io")(server);

// localhost:3000으로 서버에 접속하면 클라이언트로 index.html을 전송한다
app.get("/", function (req, res) {
  res.sendFile(__dirname + "/chat.html");
});

const users = {}; // 사용자 저장을 위한 객체 (사용자 ID와 소켓을 연결)
// namespace /chat에 접속한다.
var chat = io.of("/chat").on("connection", function (socket) {
  socket.on("chat message", function (data) {
    console.log("message from client: ", data, socket.id);
    users[socket.id] = {
      id: socket.id,
      name: data.name,
    };
    var name = (socket.name = data.name);
    var room = (socket.room = data.room);
    let to = data.to;

    // room에 join한다

    // room에 join되어 있는 클라이언트에게 메시지를 전송한다
    const msg = {
      from: {
        name,
        room,
      },
      msg: data.msg,
    };
    if (to) {
      const targetSocket = Object.values(users).find(
        (user) => user.name === to
      );
      if (targetSocket) {
        console.log(to, targetSocket);
        chat.to(targetSocket.id).emit("chat message", msg);
      }
    } else {
      socket.join(room);
      chat.to(room).emit("chat message", msg);
    }
  });
});

server.listen(4000, function () {
  console.log("Socket IO server listening on port 4000");
});

node chat.js로 서버를 먼저 켜보자.

server.listen(4000, function () {   console.log(“Socket IO server listening on port 4000”); });

원하는 포트를 설정해 주면 된다. 저는 4000번으로 설정했습니다.

app.get(“/”, function (req, res) {
  res.sendFile(__dirname + “/chat.html”);
});으로 알수있듯이 루트 경로를 입력하면 채팅화면이 나옵니다.

To는 필수값은 아니고  옵션값입니다. 원하는 대화 상대가 있을때 저곳에 사용자의 이름을 입력하면 그 사람에게만 대화가 보내집니다.

var server = require(“http”).createServer(app);
var io = require(“socket.io”)(server);

먼저 http server를 하나 만들고 http server를 socket.io server로 upgrade 코드입니다.  이렇게 서버에는 express, socket.io서버 두개의 서버가 작동하게 됩니다.

13번째 라인을 보면

var chat = io.of(“/chat”).on(“connection”, function (socket) {
namespace /chat으로 설정했습니다. 이부분은 생략하시고 그냥 io.on 이렇게 진행하셔도 됩니다.
 

클라이언트에 소캣통신을 하는 부분은

chat.to(room).emit(“chat message”, msg); 이 코드입니다. 같은 방에 들어있는 사용자들만 해당 메시지가 보이도록 하기 위하여 to(room)을 사용하였습니다.
 
특정 사용자에게만 메시지를 보내기 위해서는 to(room) 부분에 메시지를 보낼 사용자의 socket.id를 알아야 합니다. 그러기 위해서 통신을 하는 사용자의 정보를 메소드 초반에
저장 하는 코드를 만들었습니다.
    users[socket.id] = {
      id: socket.id,
      name: data.name,
    };
id, name을 가지는 객채의 배열로서 저장하고 메시지를 보내고자 할때 이름으로 찾아서 보내면 통신이 됩니다.
const targetSocket = Object.values(users).find(
    (user) => user.name === to
);
chat.to(targetSocket.id).emit(“chat message”, msg);
 

참조

Leave A Reply

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다