작성
·
82
0
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문 전에 다음을 꼭 확인해주세요.
1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://bit.ly/3fX6ygx)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)
질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)
[질문 내용]
안녕하세요 채팅 프로그램 작성 도중 여쭤볼 게 있어 남기게되었습니다
위 사진은 제 콘솔출력창입니다 왼쪽사용자는 kim : hi라는 메시지를 보냈고, 오른쪽 사용자는 han: hello라는 메시지를 보냈는데요, 문제는 메시지를 보내달라는 문장과 다른 사용자가 보낸 메시지 내용이 겹친다는 것입니다
위 사진은 제가 해결해보려는 시도로 static메소드를 lock을 사용해서 만들었습니다. 하지만 결과가 똑같았습니다. 해결방법이 궁금합니다! 그리고 lock을 걸어서 사용했는데 왜 결과가 똑같은지도 궁금합니다...답변해주시면 감사하겠습니다
아래는 제 코드를 보여드리겠습니다!
1.Client 메세지 보내는 부분 클래스입니다
public class ClientSecond {
private static final int PORT = 12345;
static Socket socket;
static DataOutputStream output;
static DataInputStream input;
public static void main(String[] args) throws IOException {
try {
socket = new Socket("localhost", PORT);
output = new DataOutputStream(socket.getOutputStream());
ClientReceiverSecond clientReceiverSecond = new ClientReceiverSecond(socket);
Thread thread = new Thread(clientReceiverSecond);
thread.start();
System.out.println("Chatting Program");
System.out.print("사용자의 이름을 입력하세요 : ");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
output.writeUTF(name); //1.이름전송
while (true) {
//System.out.print("메세지를 입력해주세요 : ");
ClientOutput.printMessage();
String message = scanner.nextLine();
output.writeUTF(message); //2.메세지전송
if (message.equals("exit")) {
System.out.println("채팅 프로그램을 종료합니다. ");
break;
}
}
}finally {
output.close();
socket.close();
}
}
}
각 클라이언트에게 다른 사용자의 메세지를 보내는 클래스입니다
public class ClientReceiverSecond implements Runnable {
private static Socket socket;
static DataInputStream input;
public ClientReceiverSecond(Socket socket){
this.socket = socket;
}
@Override
public void run() {//다른 사용자들의 메세지 확인
try {
while (true) {
input = new DataInputStream(socket.getInputStream());
String other_messages = input.readUTF(); //사용자의 이름과 메시지 분리 필요
//System.out.println(other_messages);
ClientOutput.printMessage(other_messages);
//todo
if (other_messages.equals("exit")) {
System.out.println("채팅을 종료합니다. ");
break;
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
input.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
클라이언트와 통신하는 세션 클래스인데요 혹시 몰라서 추가로 올려보겠습니다
public class SessionSecond implements Runnable{
private Socket socket;
private SessionManagerSecond sessionManagerSecond;
DataInputStream input = null;
DataOutputStream output = null;
public SessionSecond(Socket soket, SessionManagerSecond sessionManagerSecond) {
this.socket = soket;
this.sessionManagerSecond = sessionManagerSecond;
sessionManagerSecond.add(this);
}
public void send(String message) throws IOException {
output = new DataOutputStream(socket.getOutputStream());
String messages[] = message.split(",");
String name = messages[0];
String messagemain = messages[1];
output.writeUTF(name+" : "+messagemain);
}
@Override
public void run() {
try {
input = new DataInputStream(socket.getInputStream());
//output = new DataOutputStream(socket.getOutputStream());
String name = input.readUTF();
while (true) {
String message = input.readUTF();
if (message.equals("exit")) {
break;
}
String allmesaage = name+","+message;
sessionManagerSecond.call(allmesaage);
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
output.close();
input.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
답변 1
0
안녕하세요, 인프런 AI 인턴입니다.
지민님, 채팅 프로그램 작성 중 겪고 계신 콘솔 출력 문제에 대해 설명드리겠습니다.
현재 문제가 발생하는 원인은 여러 쓰레드가 동시에 콘솔에 출력을 시도하면서 메시지와 입력을 대기하는 문장이 겹치기 때문입니다. synchronized
블록을 사용하여 출력할 때 쓰레드 간의 충돌을 줄이려는 시도는 좋지만, 현재 코드 구조에서는 모든 출력과 입력이 적절하게 동기화되지 않아 문제가 발생할 가능성이 높습니다.
공통적인 lock 사용: ClientOutput
의 각 printMessage
메소드에서 사용하는 lock
객체는 제대로 공유되고 있어야 합니다. 모든 쓰레드가 동일한 lock
객체를 참조할 수 있도록 ClientOutput
이 기본적으로 저장하는 lock
객체가 모든 사용자의 콘솔 출력을 담당할 수 있도록 확인해야 합니다.
입력과 출력의 동기화 분리: 입력(prompt)를 받는 부분과 다른 사용자의 메시지를 화면에 출력하는 부분을 잘 분리하여 처리할 필요가 있습니다. 예를 들어, 사용자로부터 입력을 받을 때는 다른 사용자의 메시지를 출력하지 못하도록 동기화 구문을 변경해야 합니다.
버퍼 사용: 만약 위 두 가지 방법으로도 문제가 해결되지 않는다면, 사용자 입력을 받을 때와 메시지를 출력할 때 두 개의 큐나 버퍼를 사용하여 데이터를 처리하는 방법을 고려해보세요. 즉, 수신된 메시지는 출력 버퍼에 저장하고, 사용자 입력이 완료되면 한 번에 큐에 저장된 메시지를 출력하는 식입니다.
문제 해결에 도움이 되기를 바라며, 궁금한 점이 있으면 언제든지 추가 질문 남겨주세요. 작업에 행운을 빕니다!