[Node.js] 1:1 채팅 구현하기

仁惠·2021년 7월 4일
1

Node.js

목록 보기
1/2
post-thumbnail

1. Socket.IO 사용하기

웹은 기본적으로 요청을 하고 응답을 받고 끊게 되어 있음.
But, 실시간 메시지는 연결을 끊지 않고 유지하는 것을 기본으로 함.
웹 서버는 연결 유지가 잘 안된다는 문제가 생김.
So, 웹 서버를 이용하지 않고 Soket서버를 사용(Websocket프로토콜). Soket.IO는 웹 Soket을 편리하게 사용할 수 있게 만들어준 라이브러리. Node.js기반이고 멀티 디바이스(web,android,ios,windows)를 지원하며 websocket을 지원하지 않는 browser도 지원함.

% npm install socket.io --save
% npm install cors --save

CORS도 사용해야 함. --> 다른 웹서버도 접근할 수 있게 해줌.

두 개다 외부 모듈이라 이걸 사용해줄 수 있게 코드 작성.

// socket.io모듈 불러들이기
var socketio = require('socket.io');
// cors사용 - 클라이언트에서 ajax로 요청하면 CORS지원
var cors = require('cors');

...

//cors를 미들웨어로 사용하도록 등록
app.use(cors());

...

//socket.io 서버 시작
var io = socketio.listen(server); 
//웹 서버 위에서 websocket으로 들어오는 요청을 받아서 처리할 수 있는 준비가 됨
console.log('socket.io 요청을 받아들일 준비가 되었습니다.');

[클라이언트] ---웹소켓 요청---> 웹서버(3000port)

웹 브라우저의 클라이언트가 웹소켓을 통해서 요청을 보내면 웹 서버 위에서 똑같은 3000번 port라 하더라도 프로토콜이 다름(왔다 갔다 하는 데이터 형식). 데이터를 받아서 Socket.io모듈에서 처리해줄 준비가 됨(이게 listen()메소드, attach메소드도 있음)

socket.io는 이벤트기반으로 처리함
클라이언트가 서버로 보낼 때 : init
클라이언트가 보내온 이벤트를 받을 때 on이 됨

io.sockets.on('connection', function(socket){
	console.log('connection info -> ' + socket.request.connection._peername);
	socket.remoteAddress = socket.request.connection._peername.address;
	socket.remotePort = socket.request.connection_peername.port;
});

socket이 on이라는 메소드를 가지고 있음
connection이라는 이벤트를 가짐. 함수가 socket이라는 파라미터를 가짐
클라이언트가 어떤 IP주소와 어떤 PORT에서 접속했는지 알고 싶을 때 사용하기 위해 socket객체에 속성을 추가해둠 (socket.remoteAddress, socket.remotePort)

연결을 맺어줄려면 접속이 가능한 클라이언트가 필요 → html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>채팅 클라이언트 01</title>
    <script src="./jquery-3.1.1.min.js"></script>
    <script src="socket.io.js"></script>
    <script>
        $(function(){

        });
        function connect(){
            var host = $('#hostInput').val();
            var port = $('#portInput').val();

            connectToServer(host, port);
        }
        function connectToServer(host, port){
            var url = 'http://' + host + ':' + port;
            var options = {
                forceNew:true
            };
            var socket = io.connect(url, options);
            
            socket.on('connect', function(){
                println('웹소켓 서버에 연결됨 -> ' + url);
            });

            socket.on('disconnect', function(){
                println('웹소켓 연결 종료됨.');
            });
        }

        function println(data){
            console.log(data);
            $('#results').append('<p>' + data + '</p>');
        }
    </script>
</head>
<body>
    <h3>채팅클라이언트 01</h3>
    <br>
    <div>
        <input type="text" id="hostInput" value="localhost">
        <input type="text" id="portInput" value="3000">
        <input type="button" id="connectButton" value="연결하기" onclick="connect()">
    </div>
    <hr>
    <p>결과</p>
    <div id="results"></div>
</body>
</html>


서버와 연결이 되었음을 확인.


					▼▽구조▽▼

구조

2.서버에서 보낸 메시지 받기

emit()으로 보내고 on()으로 받음

    // 'message' 이벤트를 받았을 때의 처리
    socket.on('message', function(message) {
    	console.log('message 이벤트를 받았습니다.' + JSON.stringify(message));
    	
        if(message.recepient =='ALL') {
            // 나를 포함한 모든 클라이언트에게 메시지 전달
        	console.log('나를 포함한 모든 클라이언트에게 message 이벤트를 전송합니다.')
            io.sockets.emit('message', message);
        }
    });

io.sockets.emit() 은 나를 포함한 모든 클라이언트에게 전송하고,
socket.broadcast.emit()은 나를 제외한 모든 클라이언트에게 전송함.

3.1:1채팅하기

진행단계
내가 지정한 사람한테 메세지를 보내는 것 = 메시지를 보낼 때 부터 받는 사람을 지정
→ 받는 사람의 ID가 필요
→ 로그인 기능 추가

로그인 기능 추가하기

    // 'login' 이벤트를 받았을 때의 처리
    socket.on('login', function(input) {
    	console.log('login 이벤트를 받았습니다.' + JSON.stringify(input));

        // 기존 클라이언트 ID가 없으면 클라이언트 ID를 맵에 추가
        login_ids[input.id] = socket.id;
        socket.login_id = input.id;

        // 응답 메시지 전송
        sendResponse(socket, 'login', '200', '로그인되었습니다.');
    });

일대일 채팅 대상에게 메시지 전달

// 'message' 이벤트를 받았을 때의 처리
    socket.on('message', function(message) {
    	console.log('message 이벤트를 받았습니다.' + JSON.stringify(message));
    	
        if (message.recepient =='ALL') {
            // 나를 포함한 모든 클라이언트에게 메시지 전달
        	console.log('나를 포함한 모든 클라이언트에게 message 이벤트를 전송합니다.')
            io.sockets.emit('message', message);
        } else {
        	// 일대일 채팅 대상에게 메시지 전달
        	if (login_ids[message.recepient]) {
        		io.sockets.connected[login_ids[message.recepient]].emit('message', message);
        		
        		// 응답 메시지 전송
                sendResponse(socket, 'message', '200', '메시지를 전송했습니다.');
        	} else {
        		// 응답 메시지 전송
                sendResponse(socket, 'message', '404', '상대방의 로그인 ID를 찾을 수 없습니다.');
        	}
        }
    });

결과창

profile
ᕕ( ᐛ )ᕗ

0개의 댓글