Post

Spring으로 실시간 채팅 서비스 만들기: WebSocket을 활용한 채팅 구축 가이드

채팅 서비스은 어떻게 만들까?


Q&A 플랫폼에 채팅 서비스를 제공하기로 했다. 채팅 서비스는 이왕 만드는 김에 실시간 채팅이 가능하도록 만들려고 한다. 또 회사에서 재택으로 스스로 공부할 수 있도록 며칠을 줘서 채팅 서비스를 한번 구축하는 것을 목표로 교육시간을 보내기로 했다.

우선 지금까지의 나의 지식으로는 채팅 시스템은 이렇게 만들어야 할 것 같았다.

  1. A라는 사람이 B와의 채팅방을 만든다.
  2. A라는 사람이 채팅을 보낸다.
  3. A가 보낸 채팅은 서버를 통해 데이터베이스에 저장된다.
  4. B라는 사람은 채팅방에 들어와 있다면 주기적으로 서버에 요청을 보내서 새로운 채팅이 있는지 확인한다.
  5. A가 보낸 채팅이 있다면 B의 화면에 띄워준다

이렇게 구현을 해야할거 같았는데 이렇게 구현을 하면 당연히 문제가 되는 것은

  1. 서버에 계속 되는 요청은 서버를 힘들게 할 것이다.
  2. 주기적으로 서버에 요청은 한다는것은 실시간이 아니다. 주기가 n 초라면 최대 n 초 동안은 실시간이 아니니까

뭘까… 다른 채팅 서비스 들은 어떻게 구현이 되어 있는거지??? 라는 생각이 들어 구글링을 시작했다.

Websocket


기존 http통신은 client 로 부터 server 에게 보내는 요청만 있었다면 websocket 은 server가 client 에게도 반대로도 그러니까 양방향으로 통신이 가능하게 한 프로토콜이다! 이런것이 있었다니… 역시 똑똑한 사람들이 많다 라는 생각을 하게 되었다. 그렇다면 아까의 프로세스는 이렇게 변할 수 있을 것이다.

  1. A 라는 사람이 B와의 채팅방을 만든다.
  2. A 라는 사람이 채팅을보낸댜ㅏ.
  3. A가 보낸 채팅은 서버를 통해 데이터 베이스에 저장된다.
  4. A가 보낸 채팅은 서버에서 client 측으로 현재 채팅방에 접속해 있는 사람들 즉 B에게 채팅을 전달한다. 이렇게 되면 서버에 요청을 계속해서 보낼 필요도 없고 실시간으로 채팅을 주고 받을 수 있게 된다!!

Spring 에서 Websocket 연결하기


우선 client 단에서 server 와 websocket 연결을 시도해야 한다.

1
2
3
var sock = new SockJS("/echo");
sock.onmessage = onMessage; // 메시지가 서버로부터왔을때
sock.onclose = onClose; // 연결 끊길때

그 다음은 server 에서 받아야하니 /echo 를 endpoint로 하도록 하여 다음과 같이 한다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RequestMapping("/echo")
@Component
public class EchoHandler extends TextWebSocketHandler {

        private List<WebSocketSession> sessions = new ArrayList<WebSocketSession>();

        @Override
        public void afterConnectionEstablished(WebSocketSession session) throws Exception {
                sessions.add(session);
        }

        @Override
        public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
                sessions.remove(session);
        }
}

client 가 /echo로 websocket 연결 요청을 보내면 위에서 afterCnnetionEstablished 가 불리고 끊어질때 (웹페이지를 벗어날때) afterConnectionClosed가 불리게 된다.

이제 연결이 완료 되었다. 그렇다면 메시지를 주고 받아야한다.

메시지 주고 받기


1
2
3
4
function sendMessage(msg){
    if($("#msg-input").val().trim().length === 0) return;
    sock.send("msg:" + $("#msg-input").val());
}

client 측에서 위와 같이 sock 에 send 를 해주면 이제 spring 의 함수가 불린다.

1
2
3
4
5
        @Override
        protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
	        {다른 WebSocketSession}.sendMessage();
        }
    

그럼 다른 websocketsession 에게 그러니까 채팅방에 접속중인 다른 session 에 sendMessage 를 해주면 된다.

그러면 서버로 부터 메세지를 전달 받는것이니 websocket 연결이 되어있는 다른 client 단에서 아래의 코드가 챡실행 되면서 실시간으로 채팅을 받게 된다!

1
2
3
4
function onMessage(msg) {
    let data = msg.data;
    // 메시지 적당한곳에 끼워넣기
}

간단한 채팅 서비스를 교육중에 만들어 보았고 이것을 토대로 Q&A 플랫폼에 채팅 서비스를 구축해야겠다!

https://github.com/bwbw-kim/chatting

This post is licensed under CC BY 4.0 by the author.

© 병욱. Some rights reserved.