i have been working on a game called roborally. And we are supposed to establish a multiples Client chat. I want to know if my server or clientHandler aren't sending messages to the clients. im Using Java and JavaFx for the Gui.
this is my classes :
Client Class :
package com.roborally.chat_gui;
import javafx.scene.layout.VBox;
import java.io.*;
import java.net.Socket;
import java.util.ResourceBundle;
import java.util.Scanner;
/**
* The Client class represents a client in the chat application. It manages the communication with the server,
* including sending and receiving messages.
*/
public class Client {
private String username;
private Socket socket;
private volatile BufferedWriter bufferedWriter;
private volatile BufferedReader bufferedReader;
private final VBox vBox;
/**
* Constructs a new Client with the specified username, socket, and VBox.
*
* @param username The username of the client.
* @param socket The socket representing the connection to the server.
* @param vBox The VBox for displaying messages in the user interface.
*/
public Client(String username, Socket socket, VBox vBox) {
this.username = username;
this.vBox = vBox;
try {
this.socket = socket;
this.bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
this.bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.username = username;
}catch (IOException e){
closeEverything(socket,bufferedReader,bufferedWriter);
e.printStackTrace();
}
}
/**
* Sends a message from the client to the server.
*
* @param messageToSend The message to be sent.
*/
public void sendMessage(String messageToSend) {
try {
bufferedWriter.write(messageToSend);
bufferedWriter.newLine();
bufferedWriter.flush();
} catch (IOException e) {
closeEverything(socket, bufferedReader, bufferedWriter);
} finally {
// Close the BufferedWriter in a finally block
try {
if (bufferedWriter != null) {
bufferedWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Listens for incoming messages from the server and displays them in the user interface.
*/
public void receiveMessageFromClient(VBox vBox) {
new Thread(() -> {
while (socket.isConnected()) {
try {
if (!socket.isClosed() && bufferedReader.ready()) {
String messageFromClient = bufferedReader.readLine();
if (messageFromClient == null) {
// Connection closed by the server
System.out.println("Server closed the connection");
break;
}
ClientController.addLabel(messageFromClient, vBox);
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("Error receiving message from Client");
break;
}
}
}).start();
}
/**
* Closes all resources associated with the client.
*
* @param socket The socket representing the connection to the server.
* @param bufferedReader The BufferedReader for receiving messages from the server.
* @param bufferedWriter The BufferedWriter for sending messages to the server.
*/
public void closeEverything(Socket socket, BufferedReader bufferedReader, BufferedWriter bufferedWriter){
try {
if (bufferedWriter != null){
bufferedWriter.close();
}
if (bufferedReader != null){
bufferedReader.close();
}
if (socket != null){
socket.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
ClientHandler class :
package com.roborally.chat_gui;
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* The ClientHandler class represents a handler for communication with a specific client in a chat application.
* It manages the input and output streams for the client, listens for incoming messages, and broadcasts messages
* from the client to all other connected clients.
*/
public class ClientHandler implements Runnable{
public List<ClientHandler> clientHandlers = new CopyOnWriteArrayList<>(); /* keep track of clients, allowing to communicate*/
private Socket socket;
private BufferedReader bufferedReader; /* read data from the client */
private BufferedWriter bufferedWriter;/* send messages from client to client*/
private String clientUsername;
private Server server;
/**
* Constructs a new ClientHandler for a connected client.
*
* @param socket The socket representing the connection to the client.
* @param clientHandlers The list of client handlers for keeping track of clients.
* @param server The reference to the server managing the communication.
*/
public ClientHandler(Socket socket, List<ClientHandler> clientHandlers, Server server) {
try {
this.socket = socket;
this.bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
this.bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.clientUsername = bufferedReader.readLine();
this.server = server;
clientHandlers.add(this);
broadCastMessage("SERVER" + clientUsername + "has entered the chat !");
} catch (IOException e) {
closeEverything();
}
}
/**
* Listens for incoming messages from the client and broadcasts them to all connected clients.
* If the client disconnects, it handles the disconnection and breaks out of the loop.
*/
@Override
public void run() {
String messageFromClient;
while (socket.isConnected()){
try {
messageFromClient = bufferedReader.readLine();
if (messageFromClient != null){
System.out.println("Received message from " + clientUsername + ": " + messageFromClient);
broadCastMessage(messageFromClient);
}else {
disconnectClient();
break;
}
} catch (IOException e) {
removeClientHandler();
break;
}
}
}
/**
* Gets the username of the client.
*
* @return The username of the client.
*/
public String getClientUsername() {
return clientUsername;
}
/**
* Disconnects the client, removes it from the list of connected clients, and broadcasts a disconnection message.
*
* @throws IOException If an I/O error occurs during disconnection.
*/
public void disconnectClient() throws IOException {
clientHandlers.remove(this);
server.disconnectClient(this);
removeClientHandler();
}
/**
* Sends a message from the client to all connected clients.
*
* @param message The message to be sent.
* @throws IOException If an I/O error occurs during message sending.
*/
public void sendMessageToClient(String message) throws IOException {
if (socket.isConnected()) {
bufferedWriter.write(message);
bufferedWriter.newLine();
bufferedWriter.flush();
} else {
disconnectClient();
}
}
/**
* Broadcasts a message from the client to all other connected clients.
*
* @param messageToSend The message to be broadcasted.
*/
public void broadCastMessage(String messageToSend) {
for (ClientHandler clientHandler : clientHandlers) {
try {
if (!clientHandler.clientUsername.equals(clientUsername)) {
System.out.println("Sending message from " + clientUsername + " to " + clientHandler.clientUsername);
clientHandler.sendMessageToClient(messageToSend);
System.out.println("Message sent to " + clientHandler.clientUsername);
}
} catch (IOException e) {
e.printStackTrace();
closeEverything();
}
}
}
/**
* Removes the client handler from the list of connected clients.
*/
public void removeClientHandler() {
clientHandlers.remove(this);
server.removeClientWriter(bufferedWriter);
broadCastMessage("Server" + clientUsername + " has left the chat !");
}
/**
* Closes all resources associated with the client handler.
*/
public void closeEverything(){
removeClientHandler();
try {
if (bufferedReader != null){
bufferedReader.close();
}
if (bufferedWriter != null){
bufferedWriter.close();
}
if (socket != null){
socket.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
**ClientController Class **:
package com.roborally.chat_gui;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import java.io.IOException;
import java.net.Socket;
import java.net.URL;
import java.util.ResourceBundle;
/**
* The ClientController class manages the interaction between the user interface and the Client.
*/
public class ClientController implements Initializable {
@FXML
private Button button_send;
@FXML
private TextField message;
@FXML
private VBox Vbox_messages;
@FXML
private ScrollPane sp_main;
private Client client;
/**
* Initializes the controller, creating a new Client instance and setting up event handlers.
*/
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
try {
String username = "YourUsername";
VBox vBox = Vbox_messages;
client = new Client(username, new Socket("localhost", 8080), vBox);
} catch (IOException e) {
e.printStackTrace();
System.out.println("Error creating Client. ");
}
Vbox_messages.heightProperty().addListener((observableValue, number, newValue) -> {
sp_main.setVvalue((Double) newValue);
});
button_send.setOnAction(event -> {
Platform.runLater(() -> {
String messageToSend = message.getText();
if (!messageToSend.isEmpty()) {
HBox hBox = new HBox();
hBox.setAlignment(Pos.CENTER_RIGHT);
hBox.setPadding(new Insets(5, 5, 5, 10));
Text text = new Text(messageToSend);
TextFlow textFlow = new TextFlow(text);
textFlow.setStyle("-fx-color: rgb(239,242,255); " +
"-fx-background-color: rgb(15,125,242);" +
" -fx-background-radius: 20px");
textFlow.setPadding(new Insets(5, 10, 5, 10));
text.setFill(Color.color(0.934, 0.945, 0, 0.966));
hBox.getChildren().add(textFlow);
Vbox_messages.getChildren().add(hBox);
client.sendMessage(messageToSend);
message.clear();
}
});
});
client.receiveMessageFromClient(Vbox_messages);
}
/**
* Adds a label to the user interface for messages received from the server.
*
* @param messageFromClient The message received from the server.
* @param vBox The VBox for displaying messages in the user interface.
*/
public static void addLabel(String messageFromClient, VBox vBox) {
HBox hBox = new HBox();
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.setPadding(new Insets(5, 5, 5, 10));
Text text = new Text(messageFromClient);
TextFlow textFlow = new TextFlow(text);
textFlow.setStyle("-fx-color: rgb(233,233,235);" +
"-fx-background-radius: 20px");
textFlow.setPadding(new Insets(5, 10, 5, 10));
hBox.getChildren().add(textFlow);
Platform.runLater(() -> {
vBox.getChildren().add(hBox);
});
}
}
And my Server cLass :
package com.roborally.chat_gui;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* The Server class manages the communication between clients in a chat application.
* It accepts incoming client connections and creates a separate {@link ClientHandler} thread for each client.
* The server handles client disconnections and broadcasts disconnection messages to all connected clients.
*/
public class Server {
private ServerSocket serverSocket;
private List<PrintWriter> clientWriters = new CopyOnWriteArrayList<>();
private List<ClientHandler> clientHandlers = new CopyOnWriteArrayList<>();
/**
* Constructs a new Server with the given ServerSocket.
*
* @param serverSocket The ServerSocket to accept client connections.
*/
public Server(ServerSocket serverSocket) {
this.serverSocket = serverSocket;
}
/**
* Starts the server by initiating the thread to accept incoming clients.
*/
public void startServer() {
new Thread(this::acceptClients).start();
}
/**
* Accepts incoming client connections and creates a ClientHandler thread for each client.
*/
private void acceptClients() {
try {
while (!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
System.out.println("A new Client has connected !");
ClientHandler clientHandler = new ClientHandler(socket, clientHandlers, this);
clientHandlers.add(clientHandler);
Thread thread = new Thread(clientHandler);
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Disconnects the specified client and broadcasts a disconnection message to all clients.
*
* @param clientHandler The ClientHandler representing the client to be disconnected.
* @throws IOException If an I/O error occurs during disconnection.
*/
public void disconnectClient(ClientHandler clientHandler) throws IOException {
clientHandlers.remove(clientHandler);
broadcastDisconnectionMessage(clientHandler.getClientUsername());
}
/**
* Broadcasts a disconnection message to all connected clients.
*
* @param username The username of the client that has disconnected.
* @throws IOException If an I/O error occurs during message broadcasting.
*/
private void broadcastDisconnectionMessage(String username) throws IOException {
String message = "Server: " + username + " has left the chat!";
for (ClientHandler handler : clientHandlers) {
handler.sendMessageToClient(message);
}
}
/**
* Removes the specified client's writer from the list of client writers.
*
* @param writer The BufferedWriter of the client to be removed.
*/
public void removeClientWriter(BufferedWriter writer) {
clientWriters.remove(writer);
}
/**
* The main method to start the server. It creates a ServerSocket on the specified port and starts the server.
*
* @param args Command-line arguments (not used).
* @throws IOException If an I/O error occurs during server initialization.
*/
public static void main (String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
Server server = new Server(serverSocket);
server.startServer();
}
}