1

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();

    }       

}
ElliottV4
  • 51
  • 7
  • Something like outlined [Here](https://stackoverflow.com/questions/14148422/what-is-the-best-way-to-pass-information-between-threads) may be a good solution for you. Using a BlockingQueue to pass information between threads. – Tim Hunter Apr 17 '20 at 19:56
  • @TimHunter Would a BlockingQueue work with each client being ran as an individual application? I'm not sure how it would be able to transfer. – ElliottV4 Apr 17 '20 at 20:08
  • You made it hard by giving each client its own thread. If you didn't have that design, the thread handling this particular bit of work could just do a little bit of work sending to each client in one go. – David Schwartz Apr 17 '20 at 23:51
  • @ElliottV4 Ah, no. That's just for multiple threads in a single program. For your case, you would just have the server act as the "meeting point" for all your clients. They tell the server what they want to say and then the server passes that on to all the other clients. You'd only use the BlockingQueue if your server uses multiple threads to handle each client. Otherwise, once the server knows the message it can pass it on to the others that connect with it. – Tim Hunter Apr 18 '20 at 00:12

1 Answers1

-1

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!

Community
  • 1
  • 1
itzFlubby
  • 2,269
  • 1
  • 9
  • 31
  • So I would need to do something like this? Client's Message -> Server Server distributes message to OutputStream All clients get message via InputStream – ElliottV4 Apr 17 '20 at 19:51
  • That didn't work. I tried to write the message from the server's input stream to the server's output stream just like how my regular messages are sent, but the clients don't receive the message. – ElliottV4 Apr 17 '20 at 20:02
  • 1
    I would approch this, by having the server store an ArrayList of its Clients(sockets). Then have the server listen to all the clients, when it gets a message, convert it to a `String`. Then loop through the ArrayList and send the message to all stored sockets. This should work. If you still encounter errors, I suggest you ask a new question, as it is very hard to find and resolve errors down here in the comments. – itzFlubby Apr 17 '20 at 20:10
  • It works now, thanks so much! Solution for anyone reading this: I created an arraylist of the connected sockets like ItzFlubby suggested, then I iterated over the list whenever the server received a message and I sent the message to each of the socket's output streams. Thanks so much for the help! – ElliottV4 Apr 17 '20 at 20:38
  • Glad I could help you! To make it clear for others that this solved your issue, please consider accepting the answer as correct, by clicking on the check-mark! – itzFlubby Apr 17 '20 at 20:43