【问题标题】:How do I send a message over multiple threads in Java?如何在 Java 中通过多个线程发送消息?
【发布时间】:2011-07-17 20:03:47
【问题描述】:

我制作了一个简单的聊天服务器和客户端,客户端将文本发送到服务器,服务器只会将文本发送回发送给它的客户端。我希望它发送给所有客户,而不仅仅是那个客户。

服务器:

import java.io.IOException;
import java.net.ServerSocket;

public class Server {

    public static void main(String[] args) throws IOException {
        ServerSocket s = null;
        boolean listening = true;
        try {
            s = new ServerSocket(5555);
        } catch (IOException e) {
            e.printStackTrace();
        }

        while(listening)
            new ServerThread(s.accept()).start();

    }

}

线程:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class ServerThread extends Thread {

    private Socket sock = null;

    public ServerThread(Socket socket) {
        super("Server Thread.");
        this.sock = socket;
    }

    public void run() {

        PrintWriter out = null;
        BufferedReader in = null;

        try {
            System.out.println(sock.getInetAddress() + " has joined.");
            out = new PrintWriter(sock.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

            String input;

            while((input = in.readLine()) != null) {
                System.out.println(input);
                out.println(input);
            }

            in.close();
            out.close();
            sock.close();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

客户:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client 
{
    public static void main(String[] args) throws IOException {
        Socket sock = null;
        PrintWriter out = null;
        BufferedReader in = null;

        try {
            sock = new Socket("127.0.0.1", 5555);
            out = new PrintWriter(sock.getOutputStream(), true);
            in = new BufferedReader(
                    new InputStreamReader(sock.getInputStream()));
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        BufferedReader stdIn = new BufferedReader(new InputStreamReader(
                System.in));
        String userInput;


        while ((userInput = stdIn.readLine()) != null) {    
            out.println(userInput);
            System.out.println(in.readLine());
        }

        out.close();
        in.close();
        sock.close();
    }

}

【问题讨论】:

标签: java networking


【解决方案1】:

让您的服务器保留List<ServerThread>。在Server 上有一个void sendAll(String) 方法,可以通过ServerThreads 访问,当他们获得信息时,sendAll() 方法告诉每个ServerThread 发送他们的信息。

您正在做的事情将需要一些异步工作(而且肯定不是微不足道的!)

【讨论】:

    【解决方案2】:

    嗯,简单地说:您正在创建这些 ServerThreads 并启动它们,但您并没有以任何方式跟踪它们。想象一下,如果你每次创建一个,你把它放在一个 HashSet 中。然后,每次客户端发送一个字符串时,您都会遍历 Set 并将字符串发送给每个客户端。当然,ServerThread 中的方法 sendMessage(String) 会使这更容易。

    【讨论】:

    • 使用 HashSet 相对于 List 的任何优势。
    • 但您不应该将消息发送给发布消息的人。
    • @glowcoder - 当您必须删除客户端会话时,它可以更好地扩展。但是,存在更严重的可扩展性问题(即线程数、套接字数),因此影响可能不会立即显着。
    【解决方案3】:
    1. 将您的客户端更改为拥有一个用于从服务器读取的线程加上一个用于从键盘读取的线程。

    2. 创建一个函数,允许服务器套接字线程相互通信并使用同步,以便一次只有一个线程写入每个输出流。所以简而言之,创建一个由所有线程共享的服务器线程列表,并将您的 PrintWriter 移动到一个带有 getter 的字段中,以便可以从外部访问它。

    【讨论】:

      【解决方案4】:

      glowcoder 和 Ernest Friedman-Hill 似乎给出了很好的建议,但我想补充一点:您是否考虑过使用观察者模式和 java 的默认实现 Observable

      Server 可以扩展 Observable 对象,ServerThread 可以实现 Observer 接口。在创建新的 ServerThreads 时,使用

      将它们注册到 Observable
      server.addObserver(serverThread);
      

      ServerThread 需要知道它所链接的服务器。 然后每当客户端发送新消息时,而不是 out.println(userInput) 执行以下操作:

      synchronized (server) {
          server.setChanged();
          server.notifyObservers(userInput);
      }
      

      您还需要实现 ServerThread.update(Observable o, Object update),在其中您将获取 serverThread 的套接字的输出流并向其写入 ((String) update)。

      请注意,这将使用一个线程向所有观察者发送消息,并将阻止其他线程处理他们的聊天,直到它发送给所有观察者。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-31
        • 2018-11-01
        • 1970-01-01
        • 2018-07-14
        • 2014-06-09
        • 1970-01-01
        • 1970-01-01
        • 2018-03-31
        相关资源
        最近更新 更多