👉🏻 코드 설명 / Code Explanation
✔️ Client.java
— nodejs 서버랑 호스트와 포트를 동일하게 맞춥니다.
Match the host and port to those of the Node.js server.
String serverAddress = "localhost";
int serverPort = 3000;
— 스레드를 사용하여 채팅 타이핑과 화면에 출력하는 부분을 분리시킵니다.
Use threads to separate the chat typing process from the screen output.
Thread receiveThread = new Thread(() -> {
try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
String serverResponse;
while ((serverResponse = in.readLine()) != null) {
// ANSI 이스케이프 코드 트릭 / ANSI Escape Code Trick
// \r: 커서를 줄 맨 앞으로 이동 / Move cursor to start of line
// \033[K: 현재 커서가 있는 줄 지우기 / Clear current line
System.out.print("\r\033[K");
// 서버 메시지 출력 / Print server message
System.out.println("[서버 응답 / Server Response]: " + serverResponse);
// 지워진 입력 프롬프트를 맨 아래에 다시 복구
// Restore the cleared input prompt at the bottom
System.out.print("보낼 메시지 / Send message: ");
System.out.flush();
}
} catch (IOException e) {
System.out.println("\n수신 스레드 종료 / Receive thread terminated.");
}
});
receiveThread.start();
1)서버로 부터 메세지를 실시간으로 받는 스레드입니다.
This is a thread that receives messages from the server in real time.
2)스레드로 분리시키지 않으면 화면이 사용자 입력만 받는 부분에서 멈춰져 있습니다.
If you don’t separate it into a thread, the screen freezes while waiting for user input.
3) 아래의 코드는 해당커서가위치한 줄을 삭제하고 커서를 가장 왼쪽으로 옮깁니다.
The code below deletes the line where the cursor is currently located and moves the cursor to the far left.
System.out.print("\r\033[K");
4)위의 ANSI 이스케이프 코드 트릭이 필요한 이유는 이 채팅 클라이언트에서 화면에 “보낼 메시지 / Send message:” 출력하는 부분이 두군데 있습니다.
The reason the ANSI escape code trick mentioned above is necessary is that this chat client outputs the text “Send message:” to the screen in two different places.
5)서버에서 메세지가 도착하면 “보낼 메시지 / Send message:”가 화면에 출력되고 내가 채팅문자를 입력하고 엔터치면 “보낼 메시지 / Send message:”가 또 출력됩니다.
When a message arrives from the server, “Send message:” is displayed on the screen; after I type a chat message and press Enter, “Send message:” appears again.
6)그래서 위의 코드에서와 메인스레드에서 System.out.print(“\r\033[K보낼 메시지 / Send message: “); 이 코드는 화면에 중복되는 문자가 발생하지 않게 정리하는 역할을 합니다.
Therefore, in the code above, the line System.out.print("\r\033[K보낼 메시지 / Send message: "); executed on the main thread serves to ensure that duplicate characters do not appear on the screen.
7)다음코드는 엔터입력이 없어도 버퍼에 저장되어 있는 문자를 화면에 표시하라는 의미입니다
The following code instructs the system to display the characters stored in the buffer on the screen without requiring the Enter key to be pressed.
System.out.flush();
— 메인스레드로 사용자의 입력을 받아서 서버로 전송합니다.
The main thread receives user input and transmits it to the server.
try (
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
Scanner scanner = new Scanner(System.in)
) {
while (true) {
String userInput = scanner.nextLine();
if ("exit".equalsIgnoreCase(userInput)) {
break;
}
out.println(userInput);
// 내가 엔터를 쳤을 때 화면에 남아있는 프롬프트를 지우고 다시 깔끔하게 출력하게 만듦
// Clears the lingering prompt when Enter is pressed and cleanly reprints it
System.out.print("\r\033[K보낼 메시지 / Send message: ");
System.out.flush();
}
}
1)데이터를 서버로 보낼 수 있는 기본적인 ‘네트워크 출력 통로(스트림)’를 소켓으로부터 얻어옵니다.
You obtain a basic ‘network output channel (stream)’ from the socket that allows you to send data to the server.
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
1) 사용자의 키보드 입력을 받을 스캐너를 준비합니다.
Prepare a scanner to receive keyboard input from the user.
Scanner scanner = new Scanner(System.in);
2)while(true){ … }는 루프문을 무한 반복하면서 루프 블록을 계속 실행합니다.while(true){ ... } repeatedly executes the loop block in an infinite loop.
3)사용자가 글자 입력후 엔터를 누르면 userInput변수에 값을 담고 다음줄로 넘어갑니다.
When the user presses Enter after typing, the value is stored in the userInput variable, and the cursor moves to the next line.
String userInput = scanner.nextLine();
4)실제 소켓을 통해 네트워크로 데이터를 전달합니다.
It transmits data over the network via an actual socket.
out.println(userInput);
5)exit를 입력하면 루프 구문을 빠져나갑니다.
Entering ‘exit’ exits the loop.
if ("exit".equalsIgnoreCase(userInput)) { break; }