I’ve been trying to find the error for 3 days now, but I just can’t do it. I am so close to give up but i have come long way now… Quick overview: Multiple clients connect via a server. These all then end up in a public chat. You can access the private chat via a button. If both customers agree, a private scene opens (private chat). Everything works so far. But the message exchange in the private scene doesn’t work smoothly (a few messages are not output at all), and I don’t know why. Can someone help me please?
package javafiles;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
public class Server {
private static final int PORT = 3141;
private CopyOnWriteArrayList<ClientHandler> clients = new CopyOnWriteArrayList<>();
private Map<ClientHandler, String> clientNames = new ConcurrentHashMap<>();
private StringBuilder chatHistory = new StringBuilder(); // Chat history
public void start() {
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("Server läuft...");
while (true) {
Socket clientSocket = serverSocket.accept();
new ClientHandler(this, clientSocket); // Start a new client handler for each client
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void addClient(ClientHandler clientHandler, String name) {
clients.add(clientHandler);
clientNames.put(clientHandler, name);
// Send chat history to newly connected client
clientHandler.sendMessage(chatHistory.toString());
}
public void removeClient(ClientHandler clientHandler) {
clients.remove(clientHandler);
clientNames.remove(clientHandler);
}
public String getClientName(ClientHandler clientHandler) {
return clientNames.get(clientHandler);
}
public void requestPrivateChat(ClientHandler requester, String recipientName) {
for (ClientHandler client : clients) {
if (clientNames.get(client).equals(recipientName)) {
client.sendMessage("Willst du mit " + clientNames.get(requester) + " einen Privatchat öffnen? (/privateResponse " + clientNames.get(requester) + " yes/no)");
requester.sendMessage("Warten auf Antwort...");
return;
}
}
requester.sendMessage("Benutzer " + recipientName + " nicht gefunden.");
}
/*public void sendPrivateMessage(String recipientName, String message) {
for (ClientHandler client : clients) {
if (clientNames.get(client).equals(recipientName)) {
client.sendMessage(message);
return;
}
}
// If recipient not found, send a message to the sender
/*for (ClientHandler client : clients) {
if (clientNames.get(client).equals(getClientName(sender))) {
client.sendMessage("Benutzer " + recipientName + " nicht gefunden.");
return;192.168.
}
}
}*/
public void sendPrivateMessage(ClientHandler sender, String recipientName, String message) {
System.out.println("Attempting to send private message");
System.out.println("Sender: " + clientNames.get(sender));
System.out.println("Recipient Name: '" + recipientName + "'");
System.out.println("Message: " + message);
ClientHandler recipientHandler = null;
for (ClientHandler client : clients) {
System.out.println("Checking client: " + client.getName());
if (client.getName().equalsIgnoreCase(recipientName)) {
recipientHandler = client;
break;
}
}
if (recipientHandler != null) {
System.out.println("Sending private message from " + clientNames.get(sender) + " to " + recipientName + ": " + message);
recipientHandler.sendMessage("Privat von " + clientNames.get(sender) + ": " + message);
sender.sendMessage("Privat von " + clientNames.get(sender) + ": " + message); // send to sender as well
} else {
sender.sendMessage("Benutzer " + recipientName + " nicht gefunden.");
System.out.println("Recipient " + recipientName + " not found.");
}
}
package javafiles;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
public class PrivateChatController {
private String empfaengerin;
private Socket socket;
private BufferedReader fromServer;
private PrintWriter toServer;
@FXML
private TextArea outputTextArea;
private int port;
@FXML
private TextField inputTextField;
@FXML
private TextArea chatArea;
@FXML
private TextField messageField;
public PrivateChatController() {
port = 3141; // Default port
}
public void initialize(String empfaengerin, final Socket socket) throws IOException {
this.empfaengerin = empfaengerin;
this.socket = socket;
fromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
toServer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
new Thread(() -> {
String message;
try {
while ((message = fromServer.readLine()) != null) {
System.out.println("NAchricht bekommen: " + message);
outputTextArea.appendText(message + "n");
System.out.println("WÜRDE ZU AREA HINZUGEFÜGT");
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
@FXML
private void sendMessage() {
String message = inputTextField.getText();
if (!message.isEmpty()) {
String prefix = "/privateMessage " + empfaengerin + " ";
String modifiedMessage = prefix + message.trim(); // Trimming any extra spaces
System.out.println("Sending message to server: " + modifiedMessage);
// Send the modified message to the server
toServer.println(modifiedMessage);
// Append only the original message to the chat area
// outputTextArea.appendText("Ich: " + message + "n");
// Clear the message field
inputTextField.clear();
}
}
}
public void handlePrivateChatResponse(ClientHandler responder, String requesterName, boolean accepted) {
ClientHandler requester = null;
for (ClientHandler client : clients) {
if (clientNames.get(client).equals(requesterName)) {
requester = client;
break;
}
}
if (requester != null) {
if (accepted) {
requester.sendMessage("Privatchat mit " + clientNames.get(responder) + " geöffnet.");
responder.sendMessage("Privatchat mit " + clientNames.get(requester) + " geöffnet.");
} else {
requester.sendMessage(clientNames.get(responder) + " hat den Privatchat abgelehnt.");
}
} else {
responder.sendMessage("Anfragender Benutzer " + requesterName + " nicht gefunden.");
}
}
public void sendClientList(ClientHandler requester) {
StringBuilder clientList = new StringBuilder("CLIENTLIST:");
for (String name : clientNames.values()) {
if (!name.equals(clientNames.get(requester))) {
clientList.append(name).append(",");
}
}
if (clientList.length() > 11) {
clientList.setLength(clientList.length() - 1); // Remove the trailing comma
}
requester.sendMessage(clientList.toString());
}
public static void main(String[] args) {
new Server().start();
}
public void broadcastMessage(String message) {
// Add timestamp if the message is not a system message
if (message.contains(":")) {
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
String uhrzeit = dateFormat.format(new Date());
message = message + "tt(" + uhrzeit + ")";
}
chatHistory.append(message).append("n"); // Append message to chat history
for (ClientHandler client : clients) {
client.sendMessage(message);
}
System.out.println(message); // Output message to server console
}
}
package javafiles;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ClientHandler implements Runnable {
private Server server;
private Socket clientSocket;
private String name;
public String getName() {
return name;
}
private PrintWriter out;
private BufferedReader in;
public ClientHandler(Server server, Socket clientSocket) {
this.server = server;
this.clientSocket = clientSocket;
new Thread(this).start();
}
public void sendPrivateMessage(String senderName, String message) {
out.println("Privat von " + senderName + ": " + message);
}
@Override
public void run() {
try {
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Handle initial message for username
String initialMessage = in.readLine();
if (initialMessage != null && initialMessage.startsWith("NAME:")) {
name = initialMessage.substring(5).trim();
System.out.println("Client name set to: " + name);
}
server.addClient(this, name);
server.broadcastMessage(name + " connected.");
String message;
while ((message = in.readLine()) != null) {
System.out.println("Nachricht bekommen von " + name + " Nachricht: " + message);
if (message.startsWith("/privateMessage")) {
String[] parts = message.split("\s+", 3); // split on whitespace, max 3 parts
if (parts.length == 3) {
String recipient = parts[1].trim();
String privateMessage = parts[2].trim();
System.out.println("Recipient: '" + recipient + "', Message: " + privateMessage);
server.sendPrivateMessage(this, recipient, privateMessage);
} else {
System.out.println("Invalid /privateMessage format: " + message);
}
} else if (message.startsWith("/privateRequest")) {
String[] parts = message.split("\s+", 2); // split on whitespace, max 2 parts
if (parts.length == 2) {
String recipient = parts[1].trim();
server.requestPrivateChat(this, recipient);
}
} else if (message.startsWith("/privateResponse")) {
String[] parts = message.split("\s+", 3); // split on whitespace, max 3 parts
if (parts.length == 3) {
String sender = parts[1].trim();
boolean accepted = parts[2].trim().equalsIgnoreCase("yes");
server.handlePrivateChatResponse(this, sender, accepted);
}
} else if (message.equals("/getClients")) {
server.sendClientList(this);
} else {
server.broadcastMessage(name + ": " + message);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
server.removeClient(this);
server.broadcastMessage(name + " disconnected.");
closeResources();
}
}
private void closeResources() {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
if (clientSocket != null) {
clientSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String message) {
out.println(message);
}
}
package javafiles;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Optional;
public class ClientController {
private String address;
private int port;
// Connection
private Socket connectionToServer;
private BufferedReader fromServerReader;
private PrintWriter toServerWriter;
private String name; // Variable to store the user's name
@FXML
private TextArea outputTextArea;
@FXML
private TextField inputTextField;
@FXML
private Label uhrzeitLabel;
@FXML
private Button todobutton;
@FXML
private Button privateChatButton; // Button to start private chat
public ClientController() {
port = 3141; // Default port
}
@FXML
private void initialize() {
// Show popup to ask for server IP address
TextInputDialog ipDialog = new TextInputDialog();
ipDialog.setTitle("IP-Adresse eingeben");
ipDialog.setHeaderText("Bitte geben Sie die IP-Adresse des Servers ein:");
ipDialog.setContentText("IP-Adresse:");
Optional<String> ipResult = ipDialog.showAndWait();
if (ipResult.isPresent()) {
address = ipResult.get().trim(); // Trim to remove leading/trailing spaces
// Check if the entered IP address is valid (add your validation logic here)
if (isValidIPAddress(address)) {
// Show popup to ask user preference for name usage
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Name statt IP verwenden");
alert.setHeaderText("Möchten Sie Ihren Namen statt Ihrer IP-Adresse verwenden?");
alert.setContentText("Wählen Sie aus:");
ButtonType buttonTypeYes = new ButtonType("Ja");
ButtonType buttonTypeNo = new ButtonType("Nein");
alert.getButtonTypes().setAll(buttonTypeYes, buttonTypeNo);
alert.showAndWait().ifPresent(buttonType -> {
if (buttonType == buttonTypeYes) {
// Ask for name
name = askForName(); // Store the user's name
}
initializeConnection(); // Initialize connection with user's name (if provided) or default IP address
});
} else {
// Invalid IP address entered, exit the application
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("Ungültige IP-Adresse");
alert.setHeaderText(null);
alert.setContentText("Ungültige IP-Adresse eingegeben. Verbindung unterbrochen.");
alert.showAndWait();
Platform.exit();
}
} else {
// User clicked cancel, exit the application
Platform.exit();
System.out.println("Abbrechen gedrückt. Verbindung unterbrochen.");
}
// Erstelle einen Thread, um die Uhrzeit zu aktualisieren
Thread thread = new Thread(() -> {
while (true) {
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
String uhrzeit = dateFormat.format(new Date());
// Aktualisiere das Label auf dem JavaFX Application Thread
Platform.runLater(() -> uhrzeitLabel.setText(uhrzeit));
try {
// Warte eine Sekunde, bevor die Uhrzeit aktualisiert wird
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// Starte den Thread
thread.start();
}
private String askForName() {
TextInputDialog dialog = new TextInputDialog();
dialog.setTitle("Name eingeben");
dialog.setHeaderText("Bitte geben Sie Ihren Namen ein:");
dialog.setContentText("Name:");
Optional<String> result = dialog.showAndWait();
return result.orElse(null);
}
private void initializeConnection() {
try {
connectionToServer = new Socket();
connectionToServer.connect(new InetSocketAddress(address, port), 5000); // 5 seconds timeout
fromServerReader = new BufferedReader(new InputStreamReader(connectionToServer.getInputStream()));
toServerWriter = new PrintWriter(new OutputStreamWriter(connectionToServer.getOutputStream()), true);
// Send the name to the server
if (name != null && !name.isEmpty()) { // Check if the user provided a name
toServerWriter.println("NAME:" + name);
} else {
// Fallback to default behavior if name is not provided or is empty
name = connectionToServer.getLocalAddress().getHostAddress();
toServerWriter.println("NAME:" + name);
}
inputTextField.setPromptText("Nachricht eingeben");
new Thread(() -> {
try {
String message;
while ((message = fromServerReader.readLine()) != null) {
if (!message.startsWith("Privat von ")) {
handleServerMessage(message);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
} catch (IOException e) {
// Verbindung fehlgeschlagen, zeige Fehler-Popup an
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("Verbindungsfehler");
alert.setHeaderText(null);
alert.setContentText("Sorry, kein Server mit dieser IP im LAN gefunden.");
alert.showAndWait();
Platform.exit(); // Beende die Anwendung
}
}
@FXML
private void sendMessage() {
String message = inputTextField.getText();
if (!message.isEmpty()) {
toServerWriter.println(message);
inputTextField.clear();
}
}
private void appendMessageToOutputTextArea(String message) {
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
String uhrzeit = dateFormat.format(new Date());
outputTextArea.appendText(message + "tt(" + uhrzeit + ")n");
}
private boolean isValidIPAddress(String ipAddress) {
// Regex pattern for IPv4 address validation
String ipv4Pattern = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
return ipAddress.matches(ipv4Pattern);
}
@FXML
private void startPrivateChat() {
Alert confirmationAlert = new Alert(Alert.AlertType.CONFIRMATION);
confirmationAlert.setTitle("Privatchat starten");
confirmationAlert.setHeaderText(null);
confirmationAlert.setContentText("Möchten Sie einen Privatchat starten?");
ButtonType buttonTypeYes = new ButtonType("Ja", ButtonBar.ButtonData.OK_DONE);
ButtonType buttonTypeCancel = new ButtonType("Abbrechen", ButtonBar.ButtonData.CANCEL_CLOSE);
confirmationAlert.getButtonTypes().setAll(buttonTypeYes, buttonTypeCancel);
Optional<ButtonType> result = confirmationAlert.showAndWait();
if (result.isPresent() && result.get() == buttonTypeYes) {
// Request the list of active clients from the server
toServerWriter.println("/getClients");
}
}
private void showClientListPopup(String[] clientNames) {
Platform.runLater(() -> {
ChoiceDialog<String> dialog = new ChoiceDialog<>(clientNames.length > 0 ? clientNames[0] : "", clientNames);
dialog.setTitle("Privatchat starten");
dialog.setHeaderText("Wählen Sie einen Teilnehmer für den Privatchat aus:");
dialog.setContentText("Teilnehmer:");
Optional<String> result = dialog.showAndWait();
result.ifPresent(this::requestPrivateChat);
});
}
private void requestPrivateChat(String recipient) {
toServerWriter.println("/privateRequest " + recipient);
}
private void handlePrivateChatRequest(String sender) {
Platform.runLater(() -> {
Alert privateChatRequestAlert = new Alert(Alert.AlertType.CONFIRMATION);
privateChatRequestAlert.setTitle("Privatchat Anfrage");
privateChatRequestAlert.setHeaderText(null);
privateChatRequestAlert.setContentText("Willst du mit " + sender + " einen Privatchat öffnen?");
ButtonType buttonTypeYes = new ButtonType("Ja");
ButtonType buttonTypeNo = new ButtonType("Nein");
privateChatRequestAlert.getButtonTypes().setAll(buttonTypeYes, buttonTypeNo);
Optional<ButtonType> result = privateChatRequestAlert.showAndWait();
if (result.isPresent()) {
String response = "/privateResponse " + sender + " " + (result.get() == buttonTypeYes ? "yes" : "no");
toServerWriter.println(response);
}
});
}
@FXML
private void handlePrivateChatResponse(String requesterName, boolean accepted) {
if (accepted) {
Platform.runLater(() -> {
try {
appendMessageToOutputTextArea("Privatchat-Anfrage von " + requesterName + " wurde angenommen.");
Stage privateChatStage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("../fxml/private.fxml"));
Parent root = loader.load();
PrivateChatController controller = loader.getController();
`your text`
// Use the same connection but identify messages for private chat
controller.initialize(requesterName, connectionToServer);
privateChatStage.setTitle("Privatchat mit " + requesterName);
privateChatStage.setScene(new Scene(root));
privateChatStage.show();
} catch (IOException e) {
e.printStackTrace();
}
});
} else {
Platform.runLater(() -> {
appendMessageToOutputTextArea("Privatchat-Anfrage von " + requesterName + " wurde abgelehnt.");
});
}
}
private void handleServerMessage(String message) {
if (message.startsWith("/private")) {
// Handle private message separately
String[] parts = message.split(":", 3);
if (parts.length == 3) {
appendMessageToOutputTextArea(parts[2]); // Display private message
}
}
else if (message.startsWith("Willst du mit")) {
String sender = message.substring(14, message.indexOf(" einen Privatchat öffnen?"));
handlePrivateChatRequest(sender);
} else if (message.startsWith("CLIENTLIST:")) {
String[] clientNames = message.substring(11).split(",");
showClientListPopup(clientNames);
} else if (message.startsWith("Privatchat mit ")) {
String requesterName = message.substring(14, message.indexOf(" geöffnet."));
handlePrivateChatResponse(requesterName, true);
} else if (message.contains(" hat den Privatchat abgelehnt.")) {
String requesterName = message.substring(0, message.indexOf(" hat den Privatchat abgelehnt."));
handlePrivateChatResponse(requesterName, false);
} else {
appendMessageToOutputTextArea(message);
}
}
}
package javafiles;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class ClientMain extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("../fxml/client.fxml"));
Parent root = loader.load();
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Chat Client");
primaryStage.show();
/*FXMLLoader loaderHome = new FXMLLoader(getClass().getResource("fxml/home.fxml"));
Parent root2 = loaderHome.load();
primaryStage.setScene(new Scene(root2));
primaryStage.setTitle("Home");
primaryStage.show();*/
}
public static void main(String[] args) {
launch(args);
}
}
lxy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.