[Socket/채팅] Socket으로 채팅 구현하기 (1)

Choi Jimin·2023년 6월 4일
1

Web

목록 보기
4/5

진행했던 프로젝트에서 socket으로 채팅 기능을 구현할 일이 있었다. 단순히 실시간 채팅 주고 받는 것은 예전에 실습이나 프로젝트로 몇 번 해봤는데, 카톡처럼 채팅방 리스트가 있고 채팅 내용을 저장하는 방식은 처음 구현해보는 것 같아서 한 번 정리해보고자 한다.


📨 채팅 워크플로우

단순 실시간 채팅

채팅 기록을 저장하지 않는 단순 실시간 채팅 기능에 대한 워크플로우를 세워보자.

워크플로우는 개발자에 따라 다양하게 나올 수 있어 밑의 예시는 참고용으로만 봐주길 바란다. (그러나 ‘단순 실시간 채팅’의 경우 워낙 단순한 구조인 만큼 대부분의 개발자가 아래와 같은 형식으로 개발을 하게 될 것이다.)

  1. 클라이언트들은 채팅 기능을 하는 브라우저에 접속한다. 이때, A-Room 라는 이름의 방으로 입장한다.

  2. 클라이언트 AB에서 Socket 연결을 시도한다.

  3. 서버에서 핸드셰이킹을 하여 Socket Session 연결을 완료한다.

  4. 클라이언트 AA-Room에 채팅을 보내기 위해 연결된 Socket session으로 서버에 메시지를 보낸다.
    이때, 메시지의 형식은 서버와 미리 정해놓은 규약(명세)으로 한다.

    예시
    {
    	"room": "A-Room",
    	"message": "Hi",
    	"sender": "A"
    }
  5. 서버에서 메시지를 받아 해당 메시지를 보내고자 하는 방의 멤버들에게 다음과 같은 메시지를 보낸다.
    예시를 기준으로 진행한다면, A-Room에 해당하는 멤버를 우선 찾고, 해당 멤버와 연결된 session을 통해 서버에서 적절한 메시지를 보내면 된다.
    이때, 메시지의 형식은 서버와 미리 정해놓은 규약(명세)으로 한다.

    예시
    {
    	"message": "Hi",
    	"sender": "A"
    }
  6. 클라이언트가 서버로부터 5번과 같은 메시지를 받으면 화면에 해당 메시지를 띄워준다.

  7. 브라우저를 끌 때 연결된 socket을 close한다.


카톡과 같은 실시간 채팅(NearBuy 채팅)

본 프로젝트에서 제공되어야 하는 채팅 페이지 UI와 관련 기능들은 다음과 같았다. 디자인에 따라 구현 구조나 방식이 달라질 수 있기 때문에 본 포스팅에서 기준이 될 채팅 UI를 참고바란다.

  • 채팅방 리스트를 확인할 수 있다.
  • 원하는 채팅방에 입장해 이전 채팅 기록을 볼 수 있고, 채팅을 보낼 수 있다.
  • 접속해 있는 채팅방에 새로운 메시지가 올 경우, 해당 메시지를 실시간으로 확인할 수 있다.
  • 접속해 있지 않는 채팅방에서 새로운 메시지가 올 경우(혹은 새로운 채팅방이 타인에 의해 만들어질 경우), 해당 채팅방이 채팅방 리스트의 최상단으로 이동한다.

위와 같이 채팅 기록을 저장하고, 여러 개의 채팅방을 갖는 실시간 채팅 기능에 대한 워크플로우를 세워보자. (WebSocket 기반, 브로드캐스팅 라이브러리X)

워크플로우는 개발자에 따라 다양하게 나올 수 있어 밑의 예시는 참고용으로만 봐주길 바란다.

  1. 클라이언트 A는 채팅 기능을 하는 브라우저에 접속한다.
  2. 클라이언트 A는 채팅방 리스트를 get하는 api를 통해 서버에 HTTP 요청을 보낸다.
  3. 서버는 A가 멤버로 있는 채팅방 리스트를 필터링하여 클라이언트에 반환한다.
  4. 클라이언트 A는 서버와 socket 연결을 시도한다.
    이때 채팅방에 입장하기 전부터 socket 연결을 시도하는 이유는, 새로운 채팅 메시지를 받았을 때마다 채팅방 리스트를 최신순으로 업데이트해야 되기 때문
  5. 서버에서 핸드셰이킹을 하여 Socket Session 연결을 완료한다.
  6. 클라이언트 A가 채팅방 리스트에서 원하는 채팅방에 접속한다. 이때, 서버와 맺어진 socket session을 통해 해당 채팅방의 채팅 기록을 요청한다.
    예시
    {
    	"room": "A-Room",
    	"event": "enter",  // 소켓 사용 시 메시지에 event type 명시하는 것이 일반적
    	"sender": "A"
    }
  7. 서버는 클라이언트 A에게 받은 메시지를 보고 연결된 session을 통해 A에게 해당 룸의 채팅 기록을 보낸다.
    예시
    {
    	"event": "sendLog",
    	"log": [
    		{
    			"sender": "B",
    			"message": "Hi"
    		},
    		{
    			"sender": "A",
    			"message": "Hello"
    		}
    	]
    }
  8. 클라이언트 A가 현재 접속한 채팅방에 채팅을 보내기 위해 연결된 socket session으로 서버에 메시지를 보낸다.
    예시
    {
    	"event": "sendMessage",
    	"room": "A-Room",
    	"message": "hihi",
    	"sender": "A"
    }
  9. 서버에서 메시지를 받아 해당 메시지를 보내고자 하는 방의 멤버들에게 다음과 같은 메시지를 보낸다.
    예시를 기준으로 진행한다면, A-Room에 해당하는 멤버를 우선 찾고, 해당 멤버와 연결된 session을 통해 서버에서 적절한 메시지를 보내면 된다.
    예시
    {
    	"event": "sendMessage",
    	****"room": "A-Room"**,**
    	"message": "hihi",
    	"sender": "A"
    }
  10. 만약 A-Room 의 멤버였던 클라이언트 B가 9번과 같은 메시지를 받았다면, 브라우저에 띄워놓은 채팅방 리스트에서 해당 채팅방 컴포넌트를 찾은 뒤 해당 방을 최상단으로 끌어올린다.
    더해서 만약 클라이언트 B가 A-Room 채팅방에 접속해 있다면, 받은 메시지를 가공하여 채팅을 UI로 띄운다.

⚠️ 주의: 모든 소켓 메시지를 보낼 때는 서버와 클라이언트가 미리 정해놓은 규약(명세)을 지킨다.


NEXT

다음에는 실제 Front에서 Socket을 적용하는 방법과 코드를 정리해볼 예정이다.

0개의 댓글

관련 채용 정보