[JAVA] BufferedReader readLine() 메소드가 동작 안할 때

선행 요약

BufferedReader를 통해 읽어들일 문자열 끝에 개행 문자(\n)가 붙었는지 확인하자. 개행 문자가 존재하는지 확인해야 하는 이유는, BufferedReader가 개행 문자를 통해 경계를 구분하기 때문이다. 개행 문자가 존재하지 않으면 여전히 데이터를 수신하고 있는것으로 판단하기 때문에, readLine() 메소드를 사용해도 데이터를 읽어올 수 없다.


소켓 통신이 굴린 거대한 스노우 볼

최근, 프로젝트에 사용할 TCP 통신 서버/클라이언트 라이브러리를 개발하고 있었다. 그런데, 서버 라이브러리 개발이 끝나고 클라이언트 라이브러리를 개발하고 있을 때 쯤, 이상한 일을 겪기 시작했다.

"뭐야, 소켓이 안 닫히고 계속 실행되고 있는데?"

내가 개발하고 있던 라이브러리는 클라이언트와 서버가 문자열을 주고받고, 작업이 끝나면 클라이언트 쪽에서 자동으로 소켓이 닫히도록 코드를 작성했다. 그런데 어찌된 영문인지, 소켓이 자동으로 닫히지 않고 계속 열려 있던 것이다.

@Test
void test() throws IOException {
    try (Socket socket = new Socket("127.0.0.1", 8888)) {
        BufferedReader in =
            new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
        BufferedWriter out =
            new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));

        String outputMessage = "!HELLO";
        out.write(outputMessage);
        out.flush();

        String inputMessage = in.readLine();
        assertEquals(inputMessage, "!WORLD");
    }
}
클라이언트 코드

위의 코드는 "!HELLO" 문자열을 보내고 "!WORLD" 문자열을 받은 뒤, 값이 동일한지 확인하고 소켓을 자동으로 닫는 테스트 코드다. 하지만, 이런 단순한 테스트 코드조차 소켓이 자동으로 닫히지 않고 계속해서 멈춰 있는 현상이 발생하고 있었다. 이 문제를 해결하기 위해 나는 빠르게 서버 쪽을 분석해 보았다.

[TRACE] Receive message: !HELLO
[TRACE] Send message: !WORLD
서버 로그

우선 서버 쪽에서는 별다른 문제 없이 "!HELLO" 문자열을 받고 "!WORLD" 문자열을 정상적으로 보내고 있는 것을 확인했다. 즉, 이 문제는 클라이언트 측에서 데이터를 수신할 때 생기는 문제라고 추측해 볼 수 있다. 이 추측을 토대로 테스트 코드에서 문제가 생길만 한 곳을 좁혀봤을 때, 문제가 생길만 한 곳은 readLine() 메소드 뿐이었다.


BufferedReader는 개행 문자로 경계를 인식한다

BufferedReader는  개행 문자를 경계로 인식한다. 즉, 문자열 끝에 \n이 존재해야만 하나의 문자열로 인식한다는 것이다. 따라서 위의 테스트와 같이 서버에서 개행 문자 없이 그냥 보내게 되면, BufferedReader는 여전히 데이터가 버퍼에 쓰이고 있는 것으로 판단한다. 그러다 보니 readLine() 메소드를 호출하더라도 읽어들일 수 있는 문자열이 없는 상태이기 때문에, 클라이언트 측에서는 계속해서 서버 쪽이 개행 문자를 송신할 때 까지 무한정 대기하게 되는 것이다. 결국 이 문제는 서버 쪽에서 송신할 메시지 끝에 개행 문자를 추가한 뒤 송신함으로써 해결할 수 있었다.


정리하며

정적 byte array를 사용하면서 데이터 송수신을 할 때 불편함을 겪다보니, 이런 문제를 줄이기 위해 버퍼를 사용했었는데, 이런 유의점이 있다는 점을 모르고 몇 시간을 삽질했다. 다른 사람들이, 이 글을 보고 똑같은 삽질을 겪지 않길 바라며 글을 마친다.


참고한 문헌 및 글

  1. https://stackoverflow.com/questions/37653589/bufferedreader-readline-not-working-as-expected