본문 바로가기

Side Project

[PROJECT] Socket.io 를 이용한 채팅 애플리케이션 (3) - 회원관리 기능 구현

[PROJECT] Socket.io 채팅 애플리케이션 (3) - 회원관리 기능 구현

Socket.io 채팅 애플리케이션 (3) - 회원관리 기능 구현

지난 시간에

회원관리 관련된 웹 디자인을 했다. 로그인과 회원가입 form 을 만들었고 이번 시간에 서버와 통신하는 것을 만들어 보겠다.

 

서버 설정 ( connection, disconnect, login, join, logout )

socket.io 로 통신을 할 것인데 기억해야 하는 것은 딱 두가지이다.

받는 코드는 on , 보내는 코드는 emit

  • 서버측에서 이벤트를 보낼 때는 io.sockets.emit("이벤트 명", data)
  • 서버측에서 이벤트를 받을 때는 socket.on("이벤트 명", function(data){ })
  • 클라이언트측에서 이벤트를 보낼때는 socket.emit("이벤트 명", data)
  • 클라이언트측에서 이벤트를 받을떄는 socket.on("이벤트 명", function(data){ })

이것만 기억하면 어떤 기능이든지 짤 수 있다.

그럼 이제 app.js 파일을 작성해 보겠다.

# /app.js
server.listen(port, () => {
    console.log(`server open ${port}`);
});
------------
io.sockets.on('connection', function (socket) {
    socket.on('disconnect', function () {
    });
});

앞으로 코드를 입력할 때 ------------ 가 있으면 위에 있는 코드 코드를 추가 시키라는 뜻이다.

가장 기본이 되는 구조이다. connection 은 연결이 되었을 때이고, disconnect 는 연결이 끊어 졌을 때를 말한다.

기본적으로 연결이 되면 콜백 함수로 socket객체를 받는데 socket 데이터 안에는 client 측의 많은 정보가 담겨져있다. ( id , namespace, connect time... 등등 )

그중에 주로 사용하는 것은 on 과 연결된 client의 고유 id 인 id 가 있다. socket.id 는 연결할 때 마다 새로운 것이 발급된다.

 

우선 join 부터 구현하겠다.

#/app.js
io.sockets.on('connection', function (socket) {
----------
socket.on("join user", function (data, cb) {
	if (joinCheck(data)) {
		cb({result: false, data: "이미 존재하는 회원입니다."});
		return false;
	} else {
		users[data.id] = {id: data.id, pw: data.pw};
		cb({result: true, data: "회원가입에 성공하였습니다."});
	}
});
    
function joinCheck(data) {
	if (users.hasOwnProperty(data.id)) {
		return true;
	} else {
		return false;
	}
}

join user 라는 이벤트를 받으면 dataidpw 를 받고 joinCheck(data)의 결과가 참이라면 콜백으로 {result: false, data: "이미 존재하는 회원입니다."}를 전달하고,

거짓이라면 users 객체에 data.iddata.pw 를 넣고 콜백으로 {result: true, data: "회원가입에 성공하였습니다."} 을 전달한다.

회원가입에 성공하면 users 에는

# id : testid , pw : testpw 입력 시
{
    testid : {
        id : "testid",
        pw : "testpw"
    }
}

이런식으로 값이 저장 된다.

joinCheck(data) 함수에서는 해당 사용자가 users 에 있는지 검사한다.

 

login 도 비슷하게 구현하였다.

#/app.js
"join user" 이벤트
----------
socket.on("login user", function (data, cb) {
	if (loginCheck(data)) {
		onlineUsers[data.id] = {roomId: 1, socketId: socket.id};
		socket.join('room' + data.roomId);
		cb({result: true, data: "로그인에 성공하였습니다."});
	} else {
		cb({result: false, data: "등록된 회원이 없습니다. 회원가입을 진행해 주세요."});
		return false;
  	}
});

function loginCheck(data) {
	if (users.hasOwnProperty(data.id) && users[data.id].pw === data.pw) {
		return true;
	} else {
		return false;
	}
}

다만 로그인에서는 onlineUsers 객체에 roomIdsocketId 를 저장한다.

roomID 는 현재 사용자가 들어가있는 방의 번호이고 default 값은 1 이다.

socketIdsocket 연결할 때 client 에 발급되는 id 를 넣었다. 이 정보는 나중에 사용자가 방을 옮기거나 귓속말 기능을 구현할때 이용될 수 있다.

마지막 회원관리 기능인 logoutdisconnect 를 구현해 보자.

# /app.js
socket.on('logout', function () {
	if (!socket.id) return;
	delete onlineUsers[getUserBySocketId(socket.id)];
});

socket.on('disconnect', function () {
	if (!socket.id) return;
	delete onlineUsers[getUserBySocketId(socket.id)];
});

function getUserBySocketId(id) {
	return Object.keys(onlineUsers).find(key => onlineUsers[key].socketId === id);
}

logout 은 사용자가 logout 버튼을 눌렀을 때 발생하고, disconnect 는 client 와 연결이 끊어 졌을때 발생한다.

하는 동작은 간단하다. 일단 socket.id 가 유효한지 검사하고 유효하다면 onlineUsers 에서 해당 socket.iddelete 시킨다.

 

클라이언트 설정

client 는 직접 코드로 설명하는 편이 쉬울 것 같다.

var socket = io.connect();
var roomId = 1;
var socketId = "";
var $userWrap = $('#userWrap');
var $contentWrap = $('#contentWrap');

$loginForm.submit(function (e) {
    e.preventDefault();
    let id = $("#loginId");
    let pw = $("#loginPw");
    if (id.val() === "" || pw.val() === "") {
        alert("check validation");
        return false;
    } else {
        socket.emit('login user', {id: id.val(), pw: pw.val()}, function (res) {
            if (res.result) {
                alert(res.data);
                socketId = socket.id;
                roomId = 1;
                id.val("");
                pw.val("");
                $userWrap.hide();
                $contentWrap.show();
            } else {
                alert(res.data);
                id.val("");
                pw.val("");
                $("#joinBtn").click();
            }
        });
    }
});

$joinForm.submit(function (e) {
    e.preventDefault();
    let id = $("#joinId");
    let pw = $("#joinPw");
    if (id.val() === "" || pw.val() === "") {
        alert("check validation");
        return false;
    } else {
        socket.emit('join user', {id: id.val(), pw: pw.val()}, function (res) {
            if (res.result) {
                alert(res.data);
                id.val("");
                pw.val("");
                $("#loginBtn").click();
            } else {
                alert(res.data);
                return false;
            }
        });
    }
});

io.connect(); 로 socket 을 연결한다.

우선 joinlogin 모두 다 validation (값 검증) 을 한다. 그리고 socket.emit 으로 서버로 이벤트를 발생시킨다. 콜백으로 서버로부터 data를 받아서 동작한다.

$userWrap.hide();$contentWrap.show(); 는 이제 로그인을 성공했으니 회원 관련된 container 들을 전부 닫고 메세지 관련 컨테이너들을 보여주는 코드이다. 아직 contentWrap 을 만들지 않았으므로

# /chat.html
<div id="userWrap"></div>
----------
<div id="contentWrap">
    메세지 콘텐트
    <span id="logoutBtn">로그아웃</span>
</div>
# /public/css/style.css
#userWrap {}
----------
#contentWrap {
    width: 100%;
    min-width: 1280px;
    display: none;
}

간단하게 테스트를 위해 추가 시켜준다.

서버를 재시작 한 후 테스트를 해보자. 로그인과 회원가입이 잘 되는 것을 확인할 수 있다.

클라이언트 측에서도 logout 을 구현해 보자. 간단하게 구현만 할것 이기 때문에 따로 스타일을 주진 않겠다.

우선 chat.html 파일을 열어보자

# /chat.html
<div id="contentWrap">
	<button id="logoutBtn"></button>
</div>

logout 버튼을 하나 만들어 준다. 그리고 script.js 파일에서

$("#logoutBtn").click(function (e) {
	e.preventDefault();
    socket.emit('logout');
    socketId = "";
    alert("로그아웃되었습니다.");
    $userWrap.show();
    $contentWrap.hide();
});

logout 이벤트를 측에 보내주고 다시 userWrap을 보여 주면 된다.

이제 저장 하고 테스트 해보자.

회원가입을 하고 로그인이 성공하면 logout 버튼이 나오고 버튼을 누르면 "로그아웃되었습니다." 라는 문구와 함께 다시 로그인 화면으로 돌아가는 것을 볼수 있다.

 

다음 시간에

회원 관련된 socket 기능을 구현해 보았다. 다음 시간에는 chat 관련 ui 화면을 제작해보겠다.