Cần giúp đỡ cách fix lỗi java socket tcp Chat multi client

Em có bài tập là viết một chương trình chat giữa các client thông qua serve với giao thức TCP và ngôn ngữ java.
Code của e khi chạy trên terminal thì rất ổn, nhưng khi viết thêm giao diện thì gặp lỗi như thằng client 1 gửi tin nhắn nhưng chỉ có serve nhận đc mà ko đẩy qua cho các client khác (khi thằng client tiếp theo nhắn thì các client khác mới nhận đc tin nhắn trước đó). Rồi khi cho thằng serve tự nó gửi tin nhắn đến các client khác cũng gặp vấn đề như vậy.Mong mọi người giúp em cách fix lỗi này với ạ

Code của em:

Client:

public class ChatClient extends JFrame {
	private JPanel contentPane;
	private JTextField txtChat;
	JTextArea txtHienThi;
	Socket client_Socket;
	String client_name = "A";

	public ChatClient() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 461, 505);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(null);
		txtChat = new JTextField();
		txtChat.setBounds(10, 425, 337, 34);
		contentPane.add(txtChat);
		txtChat.setColumns(10);
		JButton btnSend = new JButton("Send");
		btnSend.setBounds(356, 424, 91, 35);
		contentPane.add(btnSend);
		JPanel panel = new JPanel();
		panel.setBounds(0, 34, 447, 381);
		contentPane.add(panel);
		panel.setLayout(new BorderLayout(0, 0));
		txtHienThi = new JTextArea();
		panel.add(txtHienThi, BorderLayout.CENTER);
		JLabel lblNewLabel = new JLabel("Client");
		lblNewLabel.setBounds(201, 0, 45, 24);
		contentPane.add(lblNewLabel);

		btnSend.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				new readClient(client_Socket, txtHienThi).start();
				new WriteClient(client_Socket, client_name, txtChat.getText(), txtHienThi).start();
			}
		});
	}

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					ChatClient frame = new ChatClient();
					frame.setVisible(true);
					frame.client_Socket = new Socket("localhost", 8889);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
}

//Luồng đọc dữ liệu từ serve
class readClient extends Thread {
	private Socket client;
	JTextArea txtHienThi;

	public readClient(Socket client, JTextArea txtHienThi) {
		this.client = client;
		this.txtHienThi = txtHienThi;
	}

	@Override
	public void run() {
		DataInputStream dis = null;
		try {
			dis = new DataInputStream(client.getInputStream());
			String msg = dis.readUTF();
			String newMsg = txtHienThi.getText() + " \n " + msg;
			txtHienThi.setText(newMsg);
		} catch (Exception e) {
			try {
				dis.close();
				client.close();
			} catch (Exception e1) {
				System.out.println("Loi");
			}
		}
	}
}

//Luồng gửi dữ liệu đến server
class WriteClient extends Thread {
	private Socket client;
	private String name;
	private JTextArea txtHienThi; 
	String messageSend; // message which user type in chat box

	public WriteClient(Socket client, String name, String message, JTextArea txtHienThi) {
		this.client = client;
		this.name = name;
		this.messageSend = message;
		this.txtHienThi = txtHienThi;
	}

	@Override
	public void run() {
		DataOutputStream dos = null;
		try {
			dos = new DataOutputStream(client.getOutputStream());
			dos.writeUTF(name + ": " + messageSend);
			dos.flush();
			txtHienThi.setText(txtHienThi.getText() + "\n" + messageSend);
		} catch (Exception e) {
			try {
				dos.close();
				client.close();
			} catch (IOException e1) {
				System.out.println("Loi roi");
			}
		}

	}
}

Serve:

public class ChatServe {
	private int port;
	public static ArrayList<Socket> listSK; //List socket which conect server
	
	public ChatServe(int port) {
		this.port = port;
	}
	private void excute() throws IOException {
		ServerSocket serve = new ServerSocket(port);
		writeServe write = new writeServe();
		write.start();
		System.out.println("Serve listening....");
		while (true) {
			Socket socket = serve.accept();
			listSK.add(socket);
			System.out.println("Da ket noi voi "+socket);
			readServe read = new readServe(socket);
			read.start();
		}
	}
	public static void main(String[] args) throws IOException {
		listSK=new ArrayList<Socket>();
		ChatServe serve=new ChatServe(8889);
		serve.excute();
	}
}

/*
 * Luồng đọc dữ liệu:
 *   + Đọc dữ liệu từ client gửi message
 *   + Gửi dữ liệu cho các client khác
 */
class readServe extends Thread {
	private Socket socket;
	public readServe(Socket client) {
		this.socket = client;
	}
	@Override
	public void run() {
		DataInputStream dis = null;
		try {
			dis = new DataInputStream(socket.getInputStream());
			while (true) {
				String msg = dis.readUTF();
				if(msg.contains("exit")) {
					
					ChatServe.listSK.remove(socket); //remove socket which request exit
					dis.close();
					socket.close();
					System.out.println("Ngat ket noi voi "+socket);
					continue;
				}
				// Gui msg cho cac client con lai 
				for (Socket item : ChatServe.listSK) {
					if(item.getPort()==socket.getPort()) {
						continue;
					}
					DataOutputStream dos = new DataOutputStream(item.getOutputStream());
					dos.writeUTF(msg);
				}
				System.out.println(msg);
			}
		} catch (Exception e) {
			try {
				dis.close();
				socket.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}
}

//Serve  gui du lieu cho cac client
class writeServe extends Thread {
	@Override
	public void run() {
		DataOutputStream dos = null;
		Scanner sc = new Scanner(System.in);
		while (true) {
			String msg = sc.nextLine();
			try {
				for (Socket item : ChatServe.listSK) {
					dos = new DataOutputStream(item.getOutputStream());
					dos.writeUTF("Serve: "+msg);
					dos.flush();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}
}

Vấn đề là bạn khởi chạy cả 2 luồng ngay khi nút gửi được nhấn.
Có nghĩa là luồng đọc chỉ đọc 1 lần (bạn không vòng lặp) nếu nhấn nút gửi từ máy khách.
Ngược lại, không nhấn nút gửi thì máy khách sẽ không bao giờ nhận được tin từ máy chủ.

Bạn nên thiết lập luồng gửi và nhận lặp liên tục (như cách làm trên máy chủ) để nó có thể sẵn sàng nhận tin bất kì khi nào. Luồng gửi có thể không cần lặp, nhưng nhận thì phải như vậy.

4 Likes

E hiểu vấn đề rồi ạ. Cảm ơn anh/ chị ạ

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?