views:

229

answers:

2

Essentially I have a basic Java Socket server as you can see below. It allows multiple users to connect and when they send a message to it, it returns it back. However I was wondering how I could edit it so if a user sends a message to it, rather than just sending it back it sends it to everyone connected? So a basic chat server. Any help would be greatly appreciated :)

import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;

import java.io.*;
import java.net.*;

class ClientWorker implements Runnable {
  private Socket client;
  private JTextArea textArea;

  ClientWorker(Socket client, JTextArea textArea) {
   this.client = client;
   this.textArea = textArea;   
  }

  public void run(){
    String line;
    BufferedReader in = null;
    PrintWriter out = null;
    try{
      in = new BufferedReader(new InputStreamReader(client.getInputStream()));
      out = new PrintWriter(client.getOutputStream(), true);
    } catch (IOException e) {
      System.out.println("in or out failed");
      System.exit(-1);
    }

    while(true){
      try{
        line = in.readLine();
//Send data back to client
         out.println(line);
         textArea.append(line);
       } catch (IOException e) {
         System.out.println("Read failed");
         System.exit(-1);
       }
    }
  }
}

class SocketThrdServer extends JFrame{

   JLabel label = new JLabel("Text received over socket:");
   JPanel panel;
   JTextArea textArea = new JTextArea();
   ServerSocket server = null;

   SocketThrdServer(){ //Begin Constructor
     panel = new JPanel();
     panel.setLayout(new BorderLayout());
     panel.setBackground(Color.white);
     getContentPane().add(panel);
     panel.add("North", label);
     panel.add("Center", textArea);
   } //End Constructor

  public void listenSocket(){
    try{
      server = new ServerSocket(4444); 
    } catch (IOException e) {
      System.out.println("Could not listen on port 4444");
      System.exit(-1);
    }
    while(true){
      ClientWorker w;
      try{
        w = new ClientWorker(server.accept(), textArea);
        Thread t = new Thread(w);
        t.start();
      } catch (IOException e) {
        System.out.println("Accept failed: 4444");
        System.exit(-1);
      }
    }
  }

  protected void finalize(){
//Objects created in run method are finalized when 
//program terminates and thread exits
     try{
        server.close();
    } catch (IOException e) {
        System.out.println("Could not close socket");
        System.exit(-1);
    }
  }

  public static void main(String[] args){
        SocketThrdServer frame = new SocketThrdServer();
    frame.setTitle("Server Program");
        WindowListener l = new WindowAdapter() {
                public void windowClosing(WindowEvent e) {
                        System.exit(0);
                }
        };
        frame.addWindowListener(l);
        frame.pack();
        frame.setVisible(true);
        frame.listenSocket();
  }
}
A: 

You can add a little modification by providing a holder to hold all the clients. Can be a List implementation. Then you could write a broadcast method and invoke that instead of out.println(). In that method you would be doing the similar thing by the way.

Moreover, you should look into Observer Pattern to implement this effectively, plus you will get a good understanding of a design pattern too. Another pattern that would be helpful here is, Mediator Pattern.

Adeel Ansari
Sorry if this sounds rude but how would I go about doing this? I'm rather new to Java and i'm building a Server to use with another project, this is the last bit of it and I really want to get it finished :)
Ozzie
Without knowing your overall design, I wouldn't be able to suggest you anything exact. So, have a look here http://www.codeproject.com/KB/IP/c_sharp_remoting.aspx . Its a chat application example based on Observer Pattern using .NET. Will definitely provide you a good hint.
Adeel Ansari
Ok, thanks! I'll take a look!. Thats the program in its entirety ha ha
Ozzie
A: 

Every time you create a new ClientWorker in listenSocket, keep a reference to the client in a list that all the client workers have access to (whether global or - preferably - passed into them when they're created). When a client receives a message, it can cycle through the list and send the message back out to each worker. You will need to be careful when adding/removing/iterating through this list, since you're going to have a lot of threads running that could all try and access it at the same time.

Also, for correctness your access to Swing components (such as textArea.append in ClientWorker) should be done from the EDT rather than from the client's thread. See the javadocs for SwingUtilities.invokeLater.

Ash