Send to all clients
Im in need of your help 😀 So, I’m trying to build a simple Java Multi Socket Server. I sarted with this Code here: http://www.kieser.net/linux/java_server.html and modifyed it a bit. Works well, but I need to send the messages back to all client, not only to the one, who sended. Heres my modifyed code:
import java.io.*; import java.net.*; import java.util.Date; public class Main < private static int port=4444, maxConnections=0; private static Date date = new Date(); // Listen for incoming connections and handle them public static void main(String[] args) < int i=0; System.out.println("[Notice][" + date.toString() + "] - Server started!"); try< ServerSocket listener = new ServerSocket(port); Socket server; while((i++ < maxConnections) || (maxConnections == 0))< server = listener.accept(); doComms conn_c= new doComms(server); Thread t = new Thread(conn_c); System.out.println("[Notice][" + date.toString() + "] - Client connected! ID: " + i); t.start(); >> catch (IOException ioe) < System.out.println("IOException on socket listen: " + ioe); ioe.printStackTrace(); >> > class doComms implements Runnable < private Socket server; private String line; private static Date date = new Date(); doComms(Socket server) < this.server=server; >public void run () < try < // Get input from the client DataInputStream in = new DataInputStream (server.getInputStream()); PrintStream out = new PrintStream(server.getOutputStream()); while((line = in.readLine()) != null && !line.equals("exit")) < out.println("Somebody says: " + line); log("Message: " + line, 0); >log("Server closed", 0); server.close(); > catch (IOException ioe) < System.out.println("IOException on socket listen: " + ioe); ioe.printStackTrace(); >> void log(String msg, int lvl) < if(lvl == 0) < System.out.println("[Notice][" + date.toString() + "] - " + msg); >else if(lvl == 1) < System.out.println("[Warn][" + date.toString() + "] - " + msg); >else if(lvl == 2) < System.out.println("[Error][" + date.toString() + "] - " + msg); >> >
I’m sure it’s not much to do, but I don’t get it 😀 Thanks for you help! //Edit Here is the working Code for now, I’m not sure: Should I use Multicast Sockets? Do they have better performance?
import java.io.*; import java.net.*; import java.util.ArrayList; import java.util.Date; public class Main < private static int port=4444, maxConnections=0; private static Date date = new Date(); // Listen for incoming connections and handle them public static void main(String[] args) < int i=0; System.out.println("[Notice][" + date.toString() + "] - Server started!"); try< ServerSocket listener = new ServerSocket(port); Socket server; while((i++ < maxConnections) || (maxConnections == 0))< server = listener.accept(); doComms conn_c= new doComms(server, i -1); Thread t = new Thread(conn_c); System.out.println("[Notice][" + date.toString() + "] - Client connected! ID: " + i); t.start(); >> catch (IOException ioe) < System.out.println("[Error][" + date.toString() + "] - " + ioe); ioe.printStackTrace(); >> > class doComms implements Runnable < private Socket server; private String line; private int client_id; private boolean cmd = false; private DataInputStream in; private PrintStream out; private static ArrayListclients = new ArrayList(); private static Date date = new Date(); doComms(Socket server, int id) < this.server = server; this.client_id = id; clients.add(this); >public void run () < try < // Get input from the client in = new DataInputStream (server.getInputStream()); out = new PrintStream(server.getOutputStream()); while((line = in.readLine()) != null && !line.equals("shutdown") && !line.equals("exit")) < send_toAll(line, this.client_id); log("Message: " + line, 0); >if(line.equals("shutdown")) < log("Got shutdown, going down now!", 0); log("Calling to exit. ", 0); send_toAll("Going down in 5sec! See you!", this.client_id); Thread.sleep(5000); log("Exiting! See you!", 0); System.exit(0); >exit(); > catch (IOException | InterruptedException ioe) < log("IOException on socket listen: " + ioe, 2); ioe.printStackTrace(); >> void exit() < log("Client with ID: " + this.client_id + " disconnected.", 0); clients.remove(this.client_id); try < this.in.close(); this.out.close(); this.server.close(); >catch (IOException ioe) < log("IOException on socket listen: " + ioe, 2); ioe.printStackTrace(); >> void send_toAll(String msg, int id) < for (int i =0; i < clients.size(); i++) < clients.get(i).send(msg, id); >> void send(String msg, int id) < out.println("Somebody(ID: " + id + ") says: " + msg); >void log(String msg, int lvl) < if(lvl == 0) < System.out.println("[Notice][" + date.toString() + "] - " + msg); >else if(lvl == 1) < System.out.println("[Warn][" + date.toString() + "] - " + msg); >else if(lvl == 2) < System.out.println("[Error][" + date.toString() + "] - " + msg); >> >
Sending a message from server to all clients
I’m trying to code an instant messaging system. Initially, I’m doing it this way, and once I get it to work I’ll add the GUI. Once a client sends a message to the server, the server is supposed to display it to all the other clients. How can I do that? I’ve been trying a few things but it keeps displaying only to the client that sent the message. Thanks in advance! SERVER
import java.io.*; import java.net.*; class Server < //one per server static int port = 3000; private int backlog = 100; ServerSocket main; static DataOutputStream dataOut; static DataInputStream dataIn; static String scannerMessage; static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); static class MailServer extends Thread < //one per client static int index; String name = Client.name; public MailServer(int index, DataInputStream in, DataOutputStream out) < Server.dataIn = in; Server.dataOut = out; this.index = index; // thread index, one per client >public void run() < while (true) < try < String receivedMessage = dataIn.readUTF(); //print receivedMessage to all clients >catch (Exception e) < break; >> > > public Server(int port) throws Exception < this.main = new ServerSocket(port); >// start a serve public void serve() throws Exception < int index = 1; while (true) < Socket socket = this.main.accept(); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); DataInputStream dataIn = new DataInputStream(in); DataOutputStream dataOut = new DataOutputStream(out); // handle the connection // keep reading using an infintite loop System.out.println("Handling connection to Client " + index + ". "); (new MailServer(index, dataIn, dataOut)).start(); index += 1; // add one every time a new client is added >> public static void main(String[] args) throws Exception < Server s = new Server(port); System.out.println("Serving. "); s.serve(); >>
import java.io.*; import java.net.*; class Client < static String hostname = "127.0.0.1"; static int port = Server.port; static Socket socket; static String name; static class Sender extends Thread < DataOutputStream dataOut; public Sender(DataOutputStream dataOut) < this.dataOut = dataOut; >public void run() < while(true) < //get a message from the user BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); try < String message = br.readLine(); dataOut.writeUTF(message); dataOut.flush(); >catch(Exception e) < break; >> > > static class Receiver extends Thread < DataInputStream dataIn; public Receiver(DataInputStream dataIn) < this.dataIn = dataIn; >public void run() < while(true) < try < //RECEIVE A MESAGE FROM THE SERVER (ending in \n) String msg = dataIn.readUTF(); while (msg != null) < System.out.println(msg); msg = dataIn.readUTF(); >> catch(Exception e) < break; >> > > //client will require host name and the port public Client(String hostname, int port) throws Exception < socket = new Socket(hostname, port); >public void connect() throws Exception < InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); DataInputStream dataIn = new DataInputStream(in); DataOutputStream dataOut = new DataOutputStream(out); //handle the connection System.out.println("Handling connection to server. "); Thread sender = new Sender(dataOut); Thread receiver = new Receiver(dataIn); sender.start(); receiver.start(); sender.join(); receiver.join(); System.out.println("Client " + Server.MailServer.index); System.out.println("----------------------"); >public static void main(String[] args) throws Exception < Client c = new Client(hostname, port); c.connect(); >>
Update: I created a list of all the MailServer objects and then iterated through them to send the message to all the clients, as JP Moresmau suggested. but now the first Client to send something receives all the outputs. Why is this? How can I fix it. ? Thank you, and sorry if my questions seem too obvious or dumb, I’m still a Java noob:( SERVER — UPDATED
package csci2020_assignment51; import java.io.*; import java.net.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; class Server < //one per server static int port = 3000; private int backlog = 100; ServerSocket main; static DataOutputStream dataOut; static DataInputStream dataIn; static String scannerMessage; static ListmailServers = Collections.synchronizedList(new ArrayList()); static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); static class MailServer extends Thread < //one per client static int index; String name = Client.name; public MailServer(int index, DataInputStream in, DataOutputStream out) < Server.dataIn = in; Server.dataOut = out; this.index = index; // thread index, one per client >public void run() < while (true) < try < String receivedMessage = dataIn.readUTF(); String outputMessage = "Client " + index + " said: " + receivedMessage; //print receivedMessage to all clients for (MailServer mailserver : mailServers) < dataOut.writeUTF(outputMessage); >> catch (Exception e) < break; >> > > public Server(int port) throws Exception < this.main = new ServerSocket(port); >// start a serve public void serve() throws Exception < int index = 1; while (true) < Socket socket = this.main.accept(); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); DataInputStream dataIn = new DataInputStream(in); DataOutputStream dataOut = new DataOutputStream(out); // handle the connection // keep reading using an infintite loop System.out.println("Handling connection to Client " + index + ". "); MailServer mailServer = new MailServer(index, dataIn, dataOut); mailServer.start(); mailServers.add(mailServer); dataOut.writeUTF("Client " + index); index += 1; // add one every time a new client is added >> public static void main(String[] args) throws Exception < Server s = new Server(port); System.out.println("Serving. "); s.serve(); >>
Java — Send Message to all Clients
I’m creating a chat server using Socket Servers and Thread. I have 3 Classes in my Server ChatServer.java, ThreadedServer.java, and Main.java. My Client has 2 ChatClient.java, Main.java. I need to make it so when a message is sent in from a client to server, the server sends out the message to all Clients. ChatServer.java
package server; import java.io.*; import java.net.*; public class ChatServer < protected Socket s; protected Socket ss; public ChatServer() < try < ServerSocket ss=new ServerSocket(6969); Runtime.getRuntime().addShutdownHook(new Thread() < public void main(String []args) throws IOException < ss.close(); >>); while (true) < Socket s =ss.accept(); new ThreadedServer(s).start(); >>catch(Exception e) < System.out.println(e); >new ThreadedServer(s).start(); > >
package server; import java.io.*; import java.net.*; public class ThreadedServer extends Thread < protected Socket socket; public ThreadedServer(Socket clientSocket) < this.socket = clientSocket; >public void run() < try < DataInputStream dis = new DataInputStream(socket.getInputStream()); DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); while (true) < String str=(String)dis.readUTF(); String remote = socket.getInetAddress().toString(); String newmes = remote + ": " + str; dos.writeUTF(newmes); System.out.println(newmes); if (str.toUpperCase() == "QUIT") < socket.close(); break; >else if (str.toUpperCase() == "EXIT") < socket.close(); break; >> >catch(Exception e) < System.out.println(e); >> >
import java.io.*; import java.net.*; public class ChatClient < public ChatClient() < try < Socket s = new Socket("10.4.27.29",6969); Runtime.getRuntime().addShutdownHook(new Thread() < public void main(String []args) throws IOException < s.close(); >>); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); DataInputStream dis = new DataInputStream(s.getInputStream()); while (true) < String message = System.console().readLine(); dos.writeUTF(message); System.out.println(dis.readUTF()); >>catch(Exception e) < System.out.println(e); >> >
package client; public class Main < public static void main(String[] args) < ChatClient chat = new ChatClient(); >>
Regarding «making this nicer». Consider using non-blocking sockets IO. Regarding sending the message to all clients: Keep a Set of sockets on your server, and send the message to each of the sockets connected but the one being sent from
1 Answer 1
Try running this. This is one I made that works.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.HashSet; /** * A multithreaded chat room server. When a client connects the * server requests a screen name by sending the client the * text "SUBMITNAME", and keeps requesting a name until * a unique one is received. After a client submits a unique * name, the server acknowledges with "NAMEACCEPTED". Then * all messages from that client will be broadcast to all other * clients that have submitted a unique screen name. The * broadcast messages are prefixed with "MESSAGE ". * * Because this is just a teaching example to illustrate a simple * chat server, there are a few features that have been left out. * Two are very useful and belong in production code: * * 1. The protocol should be enhanced so that the client can * send clean disconnect messages to the server. * * 2. The server should do some logging. */ public class ChatServer < /** * The port that the server listens on. */ private static final int PORT = 9001; /** * The set of all names of clients in the chat room. Maintained * so that we can check that new clients are not registering name * already in use. */ private static HashSetnames = new HashSet(); /** * The set of all the print writers for all the clients. This * set is kept so we can easily broadcast messages. */ private static HashSet writers = new HashSet(); /** * The appplication main method, which just listens on a port and * spawns handler threads. */ public static void main(String[] args) throws Exception < System.out.println("The chat server is running."); ServerSocket listener = new ServerSocket(PORT); try < while (true) < new Handler(listener.accept()).start(); >> finally < listener.close(); >> /** * A handler thread class. Handlers are spawned from the listening * loop and are responsible for a dealing with a single client * and broadcasting its messages. */ private static class Handler extends Thread < private String name; private Socket socket; private BufferedReader in; private PrintWriter out; /** * Constructs a handler thread, squirreling away the socket. * All the interesting work is done in the run method. */ public Handler(Socket socket) < this.socket = socket; >/** * Services this thread's client by repeatedly requesting a * screen name until a unique one has been submitted, then * acknowledges the name and registers the output stream for * the client in a global set, then repeatedly gets inputs and * broadcasts them. */ public void run() < try < // Create character streams for the socket. in = new BufferedReader(new InputStreamReader( socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); // Request a name from this client. Keep requesting until // a name is submitted that is not already used. Note that // checking for the existence of a name and adding the name // must be done while locking the set of names. while (true) < out.println("SUBMITNAME"); name = in.readLine(); if (name == null) < return; >synchronized (names) < if (!names.contains(name)) < names.add(name); break; >> > // Now that a successful name has been chosen, add the // socket's print writer to the set of all writers so // this client can receive broadcast messages. out.println("NAMEACCEPTED"); writers.add(out); // Accept messages from this client and broadcast them. // Ignore other clients that cannot be broadcasted to. while (true) < String input = in.readLine(); if (input == null) < return; >for (PrintWriter writer : writers) < writer.println("MESSAGE " + name + ": " + input); >> > catch (IOException e) < System.out.println(e); >finally < // This client is going down! Remove its name and its print // writer from the sets, and close its socket. if (name != null) < names.remove(name); >if (out != null) < writers.remove(out); >try < socket.close(); >catch (IOException e) < >> > > >
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; /** * A simple Swing-based client for the chat server. Graphically * it is a frame with a text field for entering messages and a * textarea to see the whole dialog. * * The client follows the Chat Protocol which is as follows. * When the server sends "SUBMITNAME" the client replies with the * desired screen name. The server will keep sending "SUBMITNAME" * requests as long as the client submits screen names that are * already in use. When the server sends a line beginning * with "NAMEACCEPTED" the client is now allowed to start * sending the server arbitrary strings to be broadcast to all * chatters connected to the server. When the server sends a * line beginning with "MESSAGE " then all characters following * this string should be displayed in its message area. */ public class ChatClient < BufferedReader in; PrintWriter out; JFrame frame = new JFrame("Chatter"); JTextField textField = new JTextField(40); JTextArea messageArea = new JTextArea(8, 40); /** * Constructs the client by laying out the GUI and registering a * listener with the textfield so that pressing Return in the * listener sends the textfield contents to the server. Note * however that the textfield is initially NOT editable, and * only becomes editable AFTER the client receives the NAMEACCEPTED * message from the server. */ public ChatClient() < // Layout GUI textField.setEditable(false); messageArea.setEditable(false); frame.getContentPane().add(textField, "North"); frame.getContentPane().add(new JScrollPane(messageArea), "Center"); frame.pack(); // Add Listeners textField.addActionListener(new ActionListener() < /** * Responds to pressing the enter key in the textfield by sending * the contents of the text field to the server. Then clear * the text area in preparation for the next message. */ public void actionPerformed(ActionEvent e) < out.println(textField.getText()); textField.setText(""); >>); > /** * Prompt for and return the address of the server. */ private String getServerAddress() < return JOptionPane.showInputDialog( frame, "Enter IP Address of the Server:", "Welcome to the Chatter", JOptionPane.QUESTION_MESSAGE); >/** * Prompt for and return the desired screen name. */ private String getName() < return JOptionPane.showInputDialog( frame, "Choose a screen name:", "Screen name selection", JOptionPane.PLAIN_MESSAGE); >/** * Connects to the server then enters the processing loop. */ private void run() throws IOException < // Make connection and initialize streams String serverAddress = getServerAddress(); Socket socket = new Socket(serverAddress, 9001); in = new BufferedReader(new InputStreamReader( socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); // Process all messages from server, according to the protocol. while (true) < String line = in.readLine(); if (line.startsWith("SUBMITNAME")) < out.println(getName()); >else if (line.startsWith("NAMEACCEPTED")) < textField.setEditable(true); >else if (line.startsWith("MESSAGE")) < messageArea.append(line.substring(8) + "\n"); >> > /** * Runs the client as an application with a closeable frame. */ public static void main(String[] args) throws Exception < ChatClient client = new ChatClient(); client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); client.frame.setVisible(true); client.run(); >>
How to send data from Server to multiple Clients using Sockets?
It works well with one client,but when I start new client problem with receiving message from server arises. What am I doing wrong?
Not sure if this is related to your problem, but in your Server class you create a new instance of ServerHandler but you don’t assign it to anything. With nothing referencing it it can be garbage collected at any time.
you need in your server an arraylist of socket connections. put each client on a thread and then create a thread in your server that sends data to your clients. make sure you synchronize on your arraylist tho
@JohnSheridan That’s not correct. It extends Thread, and its constructor calls start(), so it isn’t elegible for GC until it exits.
@EJP You’re absolutely right. Must have been sleepwalking. Forgot that a running Thread is treated as a GC root and immune from GC. Thanks for picking this up.
1 Answer 1
public class Server extends Thread < private ServerSocket server; protected Listclients; public Server(int port) < try < this.server = new ServerSocket(port); System.out.println("New server initialized!"); clients = Collections .synchronizedList(new ArrayList()); this.start(); > catch (Exception e) < e.printStackTrace(); >> public void run() < while (true) < try < Socket client = server.accept(); System.out.println(client.getInetAddress().getHostName() + " connected"); ClientHandler newClient = new ClientHandler(client); clients.add(newClient); new SendMessage(clients); >catch (Exception e) < e.printStackTrace(); >> > >
ClientHandler instead of Serverhandler class:
public class ClientHandler < protected Socket client; protected PrintWriter out; public ClientHandler(Socket client) < this.client = client; try < this.out = new PrintWriter(client.getOutputStream()); >catch (IOException e) < e.printStackTrace(); >> >
Thread can be added to Client class but works fine without it.I assume because when main method called new thread automatically created:
public class Client < protected Socket client; protected BufferedReader in; public Client(String hostName, int ip) < try < this.client = new Socket(hostName, ip); this.in = new BufferedReader(new InputStreamReader( this.client.getInputStream())); String buffer = null; while ((buffer = in.readLine()) != null) < System.out.println(buffer); >> catch (UnknownHostException e) < e.printStackTrace(); >catch (IOException e) < e.printStackTrace(); >> >
Class that sends data to clients:
public class SendMessage extends Thread < protected Listclients; protected String userInput; protected BufferedReader console; public SendMessage(List clients) < this.clients = clients; this.userInput = null; this.start(); >public void run() < System.out.println("New Communication Thread Started"); if (clients.size() == 1) < System.out.println("Enter message:"); >try < if (clients.size() >0) < this.console = new BufferedReader(new InputStreamReader( System.in)); while ((this.userInput = console.readLine()) != null) < if (userInput != null & userInput.length() >0) < for (ClientHandler client : clients) < client.out.println(userInput); client.out.flush(); Thread.currentThread(); Thread.sleep(1 * 1000); >> > > > catch (Exception e) < e.printStackTrace(); >> >
Now it works! Need to make SendMessage thread sleep after flushing data. Main for server starter:
public static void main(String[] args)
public static void main(String[] args)