首页 > 解决方案 > 接收输入后如何通知所有线程

问题描述

我目前正在开发一些东西,我有一个服务器等待连接,一旦建立连接,就会创建一个线程来处理服务器和客户端之间的通信。所有这些通信都是基于字符串的,使用 InputStreamReaders 和 OutputStreamReaders,我现在需要做的是能够通过他们自己的 ServerThread 向每个连接的客户端发送消息。事物如何编写的一个简单视图是:

public final static int SERVER_PORT = 12345;   
private static int numThreads=0;

public void Server() {
    ServerSocket serverSocket = null;
    
    try{
        serverSocket = new ServerSocket(Server.SERVER_PORT);           
    } catch (IOException e) {
        e.printStackTrace();
        System.exit(-1);
    }

    while (true) {
        try {
            Socket socket = serverSocket.accept();
            numThreads++;
            new ServerThread(socket, numThreads).start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

该变量numThreads主要用于向客户端打印特定信息。在ServerThread我会:

@Override
public void run() {
    while (true) {
        String command=null;
        try{
            command = readString(); //method that reads input from Client
            //Do actions based on command
        }catch(Exception ex){
            ex.getMessage();                    
        }
    }
    //Close streams and socket
}

显示的方法的内容可能有一些错别字,因为目前它们还有很多,但应该有助于可视化问题。

为了简化客户端,让我们假设有一个客户端,它连接到服务器并将命令/消息发送到我们的ServerThread.

每次客户端连接到服务器时,ServerThread都会创建一个新的,它将不断等待客户端发送一个command. 如果这command对应于例如“发送”,我需要向连接到服务器的每个客户端发送一条消息。

我怎么能做到这一点?

标签: javamultithreadingsocketsserverclient

解决方案


这里我提供一个思路,可以通过事件监控(Observer Pattern)来解决。
可以将发布者分成单独的类。

public class ServerThread implements Runnable {

  // Used for event subscription (CopyOnWriteArrayList is not the best implementation, please adjust
  // according to project needs)
  private static final List<ServerThread> LISTENERS = new CopyOnWriteArrayList<>();

  public ServerThread(Socket socket, int num) {
    // do something ...
    LISTENERS.add(this);
  }

  @Override
  public void run() {
    while (true) {
      String command = null;
      try {
        command = readString(); // method that reads input from Client
        // Do actions based on command
        if ("send".equals(command)) {
          ServerThread.publish(new SendEvent(command));
        }
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
    // Close streams and socket
  }

  private String readString() {
    return null;
  }

  /**
   * event publishing method
   *
   * @param event
   */
  public static void publish(SendEvent event) {
    LISTENERS.forEach(listener -> listener.listen(event));
  }

  /**
   * Event processing method
   *
   * @param event
   */
  public void listen(SendEvent event) {
    // to something ...
  }
}

推荐阅读