简体   繁体   中英

How to send messages to multiple users?

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

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 .

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM