4

I'm trying to make a very simple chat program that can accommodate multiple clients. I have a multi-threaded server and can connect multiple clients to it, but the server only communicates with a single client (as it should, each client is on its own thread) I need help getting the server to send all messages from all connected clients to each client. I think I'd need to share a single object between threads? Here's the code:

server:

import java.net.ServerSocket;
import java.net.Socket;


public class ThreadedCommandServer {

    public static void main(String[] args) throws Exception {
        System.out.println("Starting server....");
        int port = 8989;


        ServerSocket ss = new ServerSocket(port);


        while(true) {
            System.out.println("Waiting for connection from client...");
            Socket socket = ss.accept();
            ServerThread st = new ServerThread(socket);
            st.start();

        }
    }

}

server thread:

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;

public class ServerThread extends Thread {

    private Socket socket = null;
    private String s;

    public ServerThread(Socket s) {
        socket = s;

    }

    public void run() {
        try {
            InputStream is = socket.getInputStream();
            ObjectInputStream ois = new ObjectInputStream(is);
            s = (String) ois.readObject();
            System.out.println("received string: " + s);
            OutputStream os = socket.getOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(os);
            oos.writeObject(s);
            System.out.println("sent object back to client...");
        } catch (Exception e) {
            System.out.println(e.toString());
        }

    }

}

client:

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;


public class Controller {

private ClientFrame cf;
private String message;
private Socket socket;
private String response;

public Controller(ClientFrame cf) {
    this.cf = cf;
}


public void sendChat(String s) {
    message = s;
    System.out.println("FROM CONTROLLER: received: " + message);
    try {
    InetAddress i = InetAddress.getByName("localhost");
    socket= new Socket(i, 8989);
    OutputStream os = socket.getOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(os);
    System.out.println("FROM CONTROLLER: sending message to the server...");
    oos.writeObject(message);
    InputStream is = socket.getInputStream();
    ObjectInputStream ois = new ObjectInputStream(is);
    System.out.println("getting string back from server....");
    response = (String) ois.readObject();
    cf.updateGUI(response);
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

}

GUI:

   import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;

    public class ClientFrame extends JFrame {

    private JTextArea chatArea;
    private JTextField type;
    private JButton submit;
    private JPanel upper;
    private JPanel lower;
    private BorderLayout bl;
    JScrollPane jsp;
    Controller c;

    public ClientFrame() {
        bl = new BorderLayout();
        upper = new JPanel();
        lower = new JPanel();
        chatArea = new JTextArea("chat goes here", 20, 30);
        c = new Controller(this);
        chatArea.setEditable(false);
        chatArea.setLineWrap(true);
        type = new JTextField("type here", 20);
        jsp = new JScrollPane(chatArea);
        new SmartScroller(jsp);
        lower.add(type);
        submit = new JButton("send");
        submit.addActionListener(new Submit());
        type.addActionListener(new Submit());
        lower.add(submit);
        upper.add(jsp);
        this.setSize(400, 600);
        this.setLayout(bl);
        this.setTitle("MattChatt");
        this.add(upper, BorderLayout.NORTH);
        this.add(lower, BorderLayout.SOUTH);
        this.setVisible(true);
        this.setResizable(false);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    public void updateGUI(String s) {
        chatArea.append("\n" + s);
    }

    private class Submit implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {

            if (type.getText().equals("")) {
                System.out.println("no text entered");
            } else {
                System.out.println("submitted");
                c.sendChat(type.getText());
                type.setText("");

            }
        }

    }

    }
Matt Slater
  • 65
  • 1
  • 2
  • 8
  • 1
    You need to store the `ServerThread` instances in some kind of array/map/list. Then, when the server receives a message from the client, loop through the values (or choose a specific person) and send it using those `ServerThread` instances' output stream. I have an example [here](http://stackoverflow.com/a/29453997/2398375) (go to the bottom where it says **EDIT**) – Vince Apr 25 '15 at 04:26
  • thank you for your answer, i'll look at this in more detail. – Matt Slater Apr 25 '15 at 04:37
  • Let me know if you have any problems understanding – Vince Apr 25 '15 at 05:52
  • @VinceEmigh, why don't you put that (and a copy of the code) into an Answer? – Brian White Apr 25 '15 at 11:58
  • @VinceEmigh i tried to implement this, but does my client have to be multithreaded (always listening?) – Matt Slater Apr 25 '15 at 15:57
  • Your application is already multithreaded (you create a new thread for each client; the `ServerThread`). You could use a non blocking alternative, which I also have an example of [here](http://stackoverflow.com/a/24617983/2398375). This allows you to listen for connections and read/write to those connections on the same thread. If you want to be able to accept connections, your server needs to be listening for them. – Vince Apr 25 '15 at 17:04

1 Answers1

3

You have no way of accessing all of the ServerThreads you create. What you need to do is group them all together in a collection, such as an ArrayList.

Or even better, a HashMap, if you would ever want to expand your application to allow private messaging, you would need to access a specific ServerThread, and with a HashMap you can do so easily.

Anyways... when it is time to send out the message, you should loop your collection through and send the message to the OutputStreams associated with each ServerThread.

Ludwig
  • 178
  • 1
  • 7