-
SSE 프로토콜을 활용하여 제작한 채팅 애플리케이션Projects/Toy Projects 2021. 9. 28. 11:13
기술 스택
- IDE
- Visual Studio Code - IntelliJ IDEA
- Language
- HTML - CSS - JavaScript - Java
- Back-end
- Spring Boot - Maven - Lombok
- Database
- Mongo DB
프로젝트 목적
ㆍ 비동기 서버의 특성을 파악한다.
ㆍ SSE 프로토콜의 동작 과정을 이해한다.
프로젝트 기능
ㆍ 아이디 입력 기능
ㆍ 채팅방 번호 입력 기능
ㆍ 채팅 기능
비동기 서버의 특성
기존의 서블릿 기반의 스프링(동기 서버)
ㆍ 기존의 서블릿 기반의 스프링은 Tomcat을 기반으로 동작하고, 동기방식을 사용한다.
ㆍ 동기 서버의 동작 방식은 위 사진과 같이 사용자의 요청이 있을 때마다 스레드가 생성된다.
ㆍ 스레드가 많아지면 context switching이 많아지게 된다.
ㆍ context switching이 많아지게 되면 서버가 느려진다는 단점이 생긴다.
Spring Boot WebFlux(비동기 서버)
ㆍ Spring Boot WebFlux는 기본적으로 Netty를 기반으로 동작한다.
ㆍ Tomcat은 요청 당 하나의 스레드가 동작하는 반면, Netty는 1개의 이벤트를 받는 스레드와 다수의 worker 스레드로 동작한다.
ㆍ 하나의 요청이 끝나고 다음 요청을 받는 동기 서버와는 다르게 비동기 서버는 대기열에 대기 정보를 저장하고 계속해서 요청을 받는다.
ㆍ 또한 비동기 서버는 context switching이 없기 때문에 서버가 빠르다는 장점이 있다.
HTTP, WebSocket, SSE
HTTP
ㆍ HTTP는 클라이언트와 서버가 한 번 연결을 맺은 후, 클라이언트 요청에 대해 서버가 응답을 마치면 맺었던 연결을 끊어 버리는 성질을 가지고 있다.
ㆍ HTTP는 클라이언트 쪽에서 요청을 할 때만 서버가 응답을 하는 방식으로 통신이 된다. 따라서 서버 쪽 데이터가 업데이트되더라도 클라이언트 쪽에서 화면을 Refresh 하지 않는 이상 바뀐 데이터가 업데이트되지 않는 문제가 발생한다.
ㆍ 이러한 문제로 인해 HTTP을 사용해서 채팅 기능을 구현하기에는 적합하지 않다.
WebSocket
ㆍ WebSocket은 서버와 클라이언트 간에 socket connection을 유지하기 때문에 언제든지 양방향 통신이 가능한 기술이다.
ㆍ 또한 WebSocket은 stateful protocol이기 때문에 클라이언트와 한 번 연결이 되면 계속 같은 라인을 사용해서 통신을 하기 때문에 HTTP 사용 시 필요 없이 발생되는 HTTP와 TCP 연결 트래픽을 피할 수 있다.
ㆍ 이러한 성질 때문에 채팅 애플리케이션과 같은 실시간 업데이트가 아주 중요한 소프트웨어에서는 WebSocket이 아주 유용하게 사용된다.
SSE
ㆍ 양방향으로 통신하는 WebSocket과는 달리 서버에서 클라이언트 쪽으로 데이터를 보내는 단방향 통신을 의미한다.
ㆍ 서버에서 클라이언트 쪽으로 연결된 라인을 통해 변경된 데이터를 지속적으로 전송할 수 있다.
ㆍ 스프링에서는 WebFlux를 통해서 간단하게 구현이 가능하며, Flux 키워드를 통해 클라이언트 측으로 계속해서 변경된 데이터를 전송할 수 있다.
서버 구현
Chat 객체
@Data @Document(collection = "chat") public class Chat { @Id private String id; private String msg; // 입력받은 메시지 private String sender; // 메시지 전송자 private Integer roomNum; // 채팅방 번호 private LocalDateTime createdAt; // 메시지 입력시간 }
ㆍ 사용자로부터 입력받은 채팅 메시지와 매핑되는 Chat 객체에 대한 정보이다.
Repository
public interface ChatRepository extends ReactiveMongoRepository<Chat, String> { @Tailable @Query("{ roomNum : ?0 }") Flux<Chat> mFindByRoomNum(Integer roomNum); }
ㆍ @Tailable은 커서를 안 닫고, 계속 유지하겠다는 의미의 애너테이션이다.
ㆍ Flux는 흐름을 의미한다. 데이터를 한번 받고 끝내는 게 아니라 계속 받겠다는 것이며, 서버에서 클라이언트 측으로 응답을 유지하면서 계속해서 데이터를 흘려보낼 수 있다.
ㆍ 클라이언트가 Controller를 통해 sender가 홍길동인 데이터를 찾는 쿼리를 실행했을 때, 다른 클라이언트에서 sender가 홍길동인 또 다른 데이터를 DB에 집어넣은 경우 @Tailable을 붙여주었다면 새로 추가된 데이터도 같이 반환된다.
ㆍ 이처럼 Controller에게 DB의 데이터를 최신화해주는 것이 @Tailable이다. 또한 최신화된 데이터는 Flux로 인해서 Controller에서 클라이언트까지 계속해서 전송된다.
Controller
@RequiredArgsConstructor @RestController public class ChatController { private final ChatRepository chatRepository; @CrossOrigin @GetMapping(value = "/chat/roomNum/{roomNum}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<Chat> findByRoomNum(@PathVariable Integer roomNum) { return chatRepository.mFindByRoomNum(roomNum) .subscribeOn(Schedulers.boundedElastic()); } @CrossOrigin @PostMapping("/chat") public Mono<Chat> setMessage(@RequestBody Chat chat) { chat.setCreatedAt(LocalDateTime.now()); return chatRepository.save(chat); } }
ㆍ findByRoomNum() 메서드는 클라이언트의 채팅방 번호에 해당하는 채팅 목록을 DB에서 반환하는 역할을 한다.
ㆍ setMessage() 메서드는 사용자로부터 입력받은 메시지를 DB에 저장하는 역할을 한다.
결과물
아이디 입력 페이지
ㆍ 프롬프트 창을 통해 채팅방에 입장할 아이디를 입력할 수 있다.
채팅방 번호 입력 페이지
ㆍ 입장할 채팅방의 번호를 입력할 수 있다.
채팅 페이지
ㆍ 아이디와 채팅방 번호를 입력받은 후 채팅에 참여할 수 있다.
GitHub - qlsdud0604/chat-app: 💬 스프링 부트를 이용하여 제작한 채팅 애플리케이션
💬 스프링 부트를 이용하여 제작한 채팅 애플리케이션. Contribute to qlsdud0604/chat-app development by creating an account on GitHub.
github.com
728x90'Projects > Toy Projects' 카테고리의 다른 글
운동시간을 기록하고 그래프를 통해 확인할 수 있는 애플리케이션 (0) 2021.09.23 CPU 스케줄링 기법들의 구현 및 벤치마킹 프로그램을 통한 모의실험 (0) 2021.09.23 메모리 교체 정책들의 구현 및 벤치마킹 프로그램을 통한 모의실험 (0) 2021.09.22 Java GUI 환경에서 작동하는 계산기 (0) 2021.09.22