이 문서는 Java Socket 기반 실시간 통신 시스템을 면접에서 설명하기 위한 정리입니다.
Java Socket과 멀티스레딩을 활용해 여러 클라이언트가 동시에 메시지를 주고받을 수 있는 실시간 채팅 시스템을 구현한 학습 프로젝트입니다.
- 처음에는 소켓 연결 후 문자열을 보내면 채팅이 안정적으로 동작할 것이라고 생각했습니다.
- 하지만 여러 클라이언트가 동시에 접속하거나 긴 메시지를 보낼 때 메시지가 잘리거나 깨지는 문제가 발생했습니다.
- 어떤 클라이언트, 어떤 스레드에서 문제가 생겼는지 로그가 부족해 원인을 추적하기 어려웠습니다.
- 클라이언트마다 독립적으로 메시지를 처리할 수 있는 서버 구조 만들기
- 연결, 메시지 전송, 종료 이벤트를 구분하기
- 수신 버퍼에서 완전한 메시지 단위만 처리하도록 개선하기
- 팀원이 같은 기준으로 문제를 확인할 수 있도록 로그 체계 정리하기
- 서버는 클라이언트 연결을 받으면 클라이언트별 처리 스레드를 할당하는 구조로 설계했습니다.
- 메시지 유형을 구분해 연결, 전송, 종료 흐름을 나눴습니다.
- 로그에는 스레드 ID, 시간, 이벤트 유형을 포함하도록 기준을 맞췄습니다.
- 긴 메시지가 나뉘어 들어올 수 있다는 점을 고려해 수신 버퍼 누적과 메시지 단위 처리 기준을 정리했습니다.
- TCP는 메시지 경계를 보장하지 않기 때문에 한 번 보낸 메시지가 한 번에 그대로 도착한다고 가정하면 안 됩니다.
- 여러 클라이언트가 동시에 접속하면 로그 순서가 섞여 문제 발생 지점을 찾기 어려웠습니다.
- 클라이언트마다 스레드를 생성하는 방식은 이해하기 쉽지만, 접속자가 늘어나면 리소스 부담이 커질 수 있습니다.
- 메시지 수신 시 버퍼에 데이터를 누적하고 완전한 단위만 처리하는 방식으로 개선했습니다.
- 로그 기준을 통일해 스레드별 동작을 추적할 수 있게 했습니다.
- 향후 개선 방향으로 Thread Pool과 Java NIO를 정리했습니다.
TCP는 스트림 기반이라서 send 한 번이 receive 한 번과 1:1로 대응된다고 볼 수 없습니다. 그래서 수신 버퍼를 누적하고, 메시지 길이나 구분자를 기준으로 완전한 메시지만 처리해야 합니다.
클라이언트별 스레드 방식은 구현과 이해가 쉽지만, 접속자가 많아질수록 스레드 생성 비용과 컨텍스트 스위칭 비용이 커질 수 있습니다. 그래서 규모가 커지면 Thread Pool이나 Java NIO를 고려해야 합니다.
동시성 문제가 발생하면 로그 순서가 섞이기 쉽습니다. 그래서 스레드 ID, 시간, 이벤트 유형을 통일해서 기록해야 어느 연결에서 문제가 발생했는지 추적할 수 있습니다.
- Thread Pool 적용
- Java NIO 기반 비동기 처리
- 메시지 프로토콜 단위 테스트 추가
- 클라이언트 재접속 처리
- 서버 종료 시 연결 정리 흐름 보강
Java Socket으로 여러 클라이언트가 동시에 접속하는 채팅 시스템을 구현했습니다. 처음에는 메시지를 보내면 그대로 받을 수 있다고 생각했지만, TCP는 스트림 기반이라 긴 메시지가 나뉘어 수신되는 문제가 있었습니다. 이를 해결하기 위해 수신 버퍼에 데이터를 누적하고 완전한 메시지 단위만 처리하는 방향으로 개선했습니다. 또 스레드 ID와 이벤트 유형을 로그에 남겨 동시 접속 상황에서도 문제를 추적할 수 있게 했습니다. 지금 다시 한다면 Thread Pool이나 Java NIO를 적용해 리소스 사용을 개선하고 싶습니다.