인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

chaelynjang님의 프로필 이미지

작성한 질문수

김영한의 실전 자바 - 고급 2편, I/O, 네트워크, 리플렉션

채팅 프로그램 - 클라이언트

채팅 프로그램 관련 질문 (join 관련)

작성

·

38

0

안녕하세요 강사님 좋은 강의 매번 잘 듣고 있습니다.

채팅 프로그램 직접 먼저 구현해보라고 하셔서 코드를 짜봤는데요, 이후 강사님이 짜신 채팅 프로그램 코드를 보며 많이 부족하다는 것을 다시 느꼈습니다.

두 코드를 비교하며 제가 짠 클라이언트 코드 중에 잘 이해가 되지 않는 부분이 있는데요,,

우선 코드는 다음과 같습니다.

package network.tcp.chat;

//...

import static util.MyLogger.log;

public class ChatClient {
    private static final int PORT = 12345;

    public static void main(String[] args) throws IOException, InterruptedException {

        try (Socket socket = new Socket("localhost", PORT);
             DataInputStream input = new DataInputStream(socket.getInputStream());
             DataOutputStream output = new DataOutputStream(socket.getOutputStream())) {
            log("채팅 소켓 연결: " + socket);
            // 채팅 메시지 송.수신 분리
            ReadHandler readHandler = new ReadHandler(input);
            WriterHandler writerHandler = new WriterHandler(output);
            Thread clientReadThread = new Thread(readHandler, "clientReadHandler");
            Thread clientWriteThread = new Thread(writerHandler, "clientWriteHandler");

            clientWriteThread.start();
            clientReadThread.start();

            clientWriteThread.join();
            clientReadThread.join();
        }
    }
}
package network.tcp.chat;

//..
import static util.MyLogger.log;

public class ReadHandler implements Runnable {
    private final DataInputStream input;
    public ReadHandler(DataInputStream input) {
        this.input = input;
    }

    @Override
    public void run() {
        while(true) {
            // 서버로부터 문자 받기
            String received = null;
            try {
                received = input.readUTF();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            log("server -> client: " + received);
        }
    }
}
package network.tcp.chat;

//..
import static util.MyLogger.log;

public class WriterHandler implements Runnable {
    private final DataOutputStream output;
    public WriterHandler(DataOutputStream output) {
        this.output = output;
    }

    @Override
    public void run() {
        Scanner scanner = new Scanner(System.in);
        while(true) {
            System.out.print("전송 문자: ");
            // 서버에 문자 보내기
            String toSend = scanner.nextLine();
            try {
                output.writeUTF(toSend);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            log("client -> server: " + toSend);
            if (toSend.equals("exit")) {
                break;
            }
        }
    }
}

물론 제 코드를 작동시켜보면 1) EOFException도 발생하고 2) 자원 정리 코드도 따로 없습니다

다만 궁금한 것은 main 에 다음의 두 코드를 넣어야 채팅 프로그램이 동작한다는 것입니다.

clientWriteThread.join();
clientReadThread.join();

앞서 보여주신 간단한 server-client 예제, 강사님이 짜신 채팅 프로그램 코드 모두 Thread.join() 메소드를 전혀 사용하지 않았는데

왜 제 코드에서는 두 코드를 넣어야 채팅 프로그램이 끊기지 않고 동작하는 것인지 자문을 구해도 될까요?ㅠ

감사합니다..!

답변 1

1

인프런 AI 인턴님의 프로필 이미지

안녕하세요, 인프런 AI 인턴입니다.
채팅 프로그램을 구현하시면서 Thread.join() 메서드에 대한 의문이 있으신 것 같습니다. 이 부분은 매우 중요한 개념인데요, 여기서 join() 메서드는 해당 스레드가 종료될 때까지 메인 스레드를 대기시키는 기능을 합니다. 이를 사용하지 않을 경우, 메인 스레드가 종료되어 프로그램이 곧바로 끝나 버릴 수 있습니다.

질문해 주신 내용과 관련하여, 여러분의 코드는 메인 스레드에서 try 블록을 벗어나면 소켓을 닫고 자원을 정리하기 때문에, 스레드를 통한 송수신 작업이 아직 끝나지 않았을 경우 프로그램이 예기치 않게 종료될 수 있습니다. 그렇기 때문에 join() 메서드를 사용하여 백그라운드 스레드가 완료될 때까지 메인 스레드를 대기시켜야 합니다.

영한님이 작성하신 코드에서는, 이러한 구조적 차이 때문에 자원을 정리함과 동시에 스레드가 자연스럽게 종료되기 때문에 join() 메서드를 사용하지 않았을 가능성이 높습니다. 따라서, 두 코드를 좀 더 비교 분석하시면서 스레드 동작 방식과 자원 정리의 차이를 주목해 보시면 좋을 듯합니다.

이와 관련된 유사 질문을 통해 추가적인 이해를 도울 수 있습니다:

강의에서 다룬 내용을 다시 한 번 돌아보시고, 코드의 흐름을 면밀히 검토해 보시길 추천드립니다. 시도하신 코드들에 대해 제안할 개선사항이 있다면 객관적인 피드백을 제공하겠습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천드립니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.