-
[Spring Boot] 브라우저 강제 종료시 소켓 연결 끊기Spring/Trouble Shooting 2023. 5. 16. 18:24
브라우저 강제 종료하면 소켓 해제는?
문제 상황
웹 소켓을 통한 채팅 서비스 구현중
클라이언트가 브라우저를 강제 종료를 해도 소켓 연결 해제가 정상적으로 이뤄지지 않았다.문제 요인
클라이언트 측에서 소켓의 Disconnect 요청을 보내오지 않았기 때문에
서버에서는 당연히 연결 되어 있음으로 판단하고, 연결을 유지했다.
정확히는 Disconnect를 보내오면 채팅방의 인원수가 줄어들면서
클라이언트가 연결을 종료했다고 로직을 작성했는데,Disconnect 요청이 안오니 채팅방 인원수가 그대로 유지되었다.
문제 해결
- 소켓의 연결 상태를 기록했다.
- 서버 측에서 클라이언트의 Disconnect 요청을 기다리지만은 않고, 스스로 판단할 수 있도록 했다.
1번 기록
public class Session { @Id @GeneratedValue @Column(name = "session_id") private Long id; @ManyToOne @JoinColumn(name = "chatroom_id") private ChatRoom chatRoom; @ManyToOne @JoinColumn(name = "member_id") private Member member; @Column private String nowSessionId;
소켓의 연결 상태를 기록하기 위해, 현재 세션 Id와 방 Id 그리고 어떤 유저인지 파악할 수 있도록 member_id를 같이 저장해줬다.
@Override public void configureClientInboundChannel(ChannelRegistration registration) { registration.interceptors(stompHandler); }
인터셉터를 작성해주고
@Override public Message<?> preSend(Message<?> message, MessageChannel channel) { StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message); switch (accessor.getCommand()) { ... case SUBSCRIBE: String roomId = accessor.getFirstNativeHeader("roomId"); Long uidFromToken = jwtService.getUidFromToken(accessor.getFirstNativeHeader("Authorization")); // SUBSCRIBE 동작시 session에 현재 유저 아이디 uid와, 메세지 헤더 정보의 roomId를 매핑해서 DB에 저장 Long sessionId = sessionService.setEnterInfo(accessor.getSessionId(), roomId, uidFromToken); chatService.countPeopleChatRoom(roomId, "SUBSCRIBE"); log.info("SUBSCRIBE : [ {} ] [ {} ] [ {} ]", sessionId, accessor.getSessionId(), roomId); break; ... }
SUBSCRIBE 실행시 DB에 저장
이렇게 해서 현재 소켓 연결 상태를 기록했다.
2번 기록
1번 기록과 마찬가지로 인터셉터에 Disconnect를 설정해서
case DISCONNECT: session = sessionRepository.findSessionByNowSessionId(accessor.getSessionId()) .orElseThrow(() -> new StompConversionException("올바른 세션이 아닙니다.")); checkCountPeople = chatService.countPeopleChatRoom(session.getChatRoom().getRoomId(), "DISCONNECT"); sessionRepository.delete(session); if (checkCountPeople) { chatRoomRepository.deleteById(session.getChatRoom().getRoomId()); } break;
소켓 연결이 자동으로 Disconnect 동작을 수행하도록 설정했다.
솔직히 왜 동작했는지 자세한 원리는 이해 못했지만,
클라이언트 Disconnect 요청 안보내고 강제종료 -> 소켓 연결 상태 이상해짐 -> 서버에서 이를 알아채면 Disconnect 동작 수행이런 식으로 동작한 것이 아닐까?