Search code examples
javamultithreadingsocketsserverclient

Java Sockets - How can I send messages to multiple threads?


I made a Chat Application (Server/Client) using Java. Note: The server is ran as its own jar file and each client is ran as its own jar file.

Each client is on their own thread.

Whenever I send messages to the server, each client receives the message, however when I send messages from the client, only the server receives the message. When the client sends a message, I want all connected clients and the server to receive the message so all of the clients can communicate together and with the server as well.

I've looked at multiple posts and videos about this, but most were too confusing for me to understand. Could someone please help me understand how I can send messages between threads? Thanks!

-- My Code --

Client:

public Client(User user, String address, int port) {

        try {
            socket = new Socket(address, port);

            ClientApplicationUI app = new ClientApplicationUI();

            app.setTitle("Chat Application - " + user.getUsername());
            app.setVisible(true);

            ServerConnection connection = new ServerConnection(socket, app);

            output = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));

            new Thread(connection).start();

            app.getButton().addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    if (app.getTextField().getText() != null && app.getTextField().getText().length() > 0) {
                        String message = MessageUtil.getMessage(Message.LOGGER_PREFIX) + " <" + user.getUsername() + "> " + app.getTextField().getText() + "\n";
                        try {
                            output.writeUTF(message);
                            output.flush();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                        }

                }

            });

        } catch (UnknownHostException e) {
            System.out.println(e);
            System.out.println("Could not connect! Reason: " + e);
        } catch (IOException e) {
            System.out.println("Could not connect! Reason: " + e);
        }

    }

ServerConnection

public class ServerConnection implements Runnable {

    @SuppressWarnings("unused")
    private Socket socket;
    private DataInputStream in;
    private ClientApplicationUI app;

    public ServerConnection(Socket socket, ClientApplicationUI app) throws IOException {
        this.socket = socket;
        this.app = app;
        in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
    }

    @Override
    public void run() {
        while (true) {
            String message;
            try {
                message = in.readUTF();
                app.logMessage(message);
            } catch (IOException e) {

                e.printStackTrace();
            }
        }

    }

}

Server

public class Server {

    private Socket socket = null;
    private ServerSocket server = null;
    private ExecutorService pool = Executors.newFixedThreadPool(4);

    public Server (int port) {

        try {

            ApplicationUI app = new ApplicationUI();
            app.setVisible(true);
            server = new ServerSocket(port);
            app.logMessage(MessageUtil.getMessage(Message.LOGGER_PREFIX) + " " + MessageUtil.getMessage(Message.INFO) + " Server started!\n");
            app.logMessage(MessageUtil.getMessage(Message.LOGGER_PREFIX) + " " + MessageUtil.getMessage(Message.INFO) + " Waiting for new connections...\n");


            while (true) {
                socket = server.accept();
                ConnectionHandler clientThread = new ConnectionHandler(socket, app);
                app.logMessage(MessageUtil.getMessage(Message.LOGGER_PREFIX) + " " + MessageUtil.getMessage(Message.INFO) + " A new client has been accepted!\n");

                pool.execute(clientThread);
            }


        } catch (IOException e) {
            e.printStackTrace();

        }

    }

    public static void main(String[] args) {
        Server server = new Server(58139);
    }
}

ConnectionHandler

public class ConnectionHandler implements Runnable {

    private Socket client;
    private ApplicationUI app;
    private DataInputStream in;
    private DataOutputStream out;

    public ConnectionHandler(Socket client, ApplicationUI app) throws IOException {
        this.client = client;
        this.app = app;
        in = new DataInputStream(new BufferedInputStream(client.getInputStream()));
        out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
    }

    @Override
    public void run() {

        try {
        app.getButton().addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (app.getTextField().getText() != null && app.getTextField().getText().length() > 0) {
                    String message = MessageUtil.getMessage(Message.LOGGER_PREFIX) + " <Server> " + app.getTextField().getText() + "\n";
                    try {
                        sendMessage(message);

                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    }

            }

        });

        String message = "";
        while (!message.equals("/stop")) {
                message = in.readUTF();
                app.logMessage(message);
        }

    } catch (IOException e) {
        System.err.println("IO exception in connection handler!");
        System.err.println(e.getStackTrace());
    } finally {
        try {
            out.close();
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    }

    private void sendMessage(String message) throws IOException {
        out.writeUTF(message);
        out.flush();

    }       

}

Solution

  • You need to understand, how sockets work. They are always Client and Server.
    There are two ways you could achieve what you want:

    First solution:
    Send the message which is meant for all clients to the server and let the server distribute the message to all the other clients. The server will need to keep track of the already connected clients, i.e. store their Socket.


    Second solution: (which totally is not advisable)
    If you want to send a message to a client of a network without haveing the actual server involved, you will need that client to act as a server, or the other way around. This means that every client will actually need to listen to every other client, instead of only the server.

    You should definitely go with the first solution!