【问题标题】:Java Sockets - How can I send messages to multiple threads?Java Sockets - 如何将消息发送到多个线程?
【发布时间】:2020-07-31 09:55:53
【问题描述】:

我使用 Java 制作了一个聊天应用程序(服务器/客户端)。注意:服务器作为自己的 jar 文件运行,每个客户端作为自己的 jar 文件运行。

每个客户端都在自己的线程上。

每当我向服务器发送消息时,每个客户端都会收到消息,但是当我从客户端发送消息时,只有服务器会收到消息。当客户端发送消息时,我希望所有连接的客户端和服务器都接收消息,以便所有客户端都可以一起通信并与服务器通信。

我查看了很多关于此的帖子和视频,但大多数都让我难以理解。 有人可以帮我理解如何在线程之间发送消息吗?谢谢!

-- 我的代码--

客户:

public Client(User user, String address, int port) {

        try {
            socket = new Socket(address, port);

            ClientApplicationUI app = new ClientApplicationUI();

            app.setTitle("Chat Application - " + user.getUsername());
            app.setVisible(true);

            ServerConnection connection = new ServerConnection(socket, app);

            output = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));

            new Thread(connection).start();

            app.getButton().addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    if (app.getTextField().getText() != null && app.getTextField().getText().length() > 0) {
                        String message = MessageUtil.getMessage(Message.LOGGER_PREFIX) + " <" + user.getUsername() + "> " + app.getTextField().getText() + "\n";
                        try {
                            output.writeUTF(message);
                            output.flush();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                        }

                }

            });

        } catch (UnknownHostException e) {
            System.out.println(e);
            System.out.println("Could not connect! Reason: " + e);
        } catch (IOException e) {
            System.out.println("Could not connect! Reason: " + e);
        }

    }

服务器连接

public class ServerConnection implements Runnable {

    @SuppressWarnings("unused")
    private Socket socket;
    private DataInputStream in;
    private ClientApplicationUI app;

    public ServerConnection(Socket socket, ClientApplicationUI app) throws IOException {
        this.socket = socket;
        this.app = app;
        in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
    }

    @Override
    public void run() {
        while (true) {
            String message;
            try {
                message = in.readUTF();
                app.logMessage(message);
            } catch (IOException e) {

                e.printStackTrace();
            }
        }

    }

}

服务器

public class Server {

    private Socket socket = null;
    private ServerSocket server = null;
    private ExecutorService pool = Executors.newFixedThreadPool(4);

    public Server (int port) {

        try {

            ApplicationUI app = new ApplicationUI();
            app.setVisible(true);
            server = new ServerSocket(port);
            app.logMessage(MessageUtil.getMessage(Message.LOGGER_PREFIX) + " " + MessageUtil.getMessage(Message.INFO) + " Server started!\n");
            app.logMessage(MessageUtil.getMessage(Message.LOGGER_PREFIX) + " " + MessageUtil.getMessage(Message.INFO) + " Waiting for new connections...\n");


            while (true) {
                socket = server.accept();
                ConnectionHandler clientThread = new ConnectionHandler(socket, app);
                app.logMessage(MessageUtil.getMessage(Message.LOGGER_PREFIX) + " " + MessageUtil.getMessage(Message.INFO) + " A new client has been accepted!\n");

                pool.execute(clientThread);
            }


        } catch (IOException e) {
            e.printStackTrace();

        }

    }

    public static void main(String[] args) {
        Server server = new Server(58139);
    }
}

连接处理程序

public class ConnectionHandler implements Runnable {

    private Socket client;
    private ApplicationUI app;
    private DataInputStream in;
    private DataOutputStream out;

    public ConnectionHandler(Socket client, ApplicationUI app) throws IOException {
        this.client = client;
        this.app = app;
        in = new DataInputStream(new BufferedInputStream(client.getInputStream()));
        out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
    }

    @Override
    public void run() {

        try {
        app.getButton().addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (app.getTextField().getText() != null && app.getTextField().getText().length() > 0) {
                    String message = MessageUtil.getMessage(Message.LOGGER_PREFIX) + " <Server> " + app.getTextField().getText() + "\n";
                    try {
                        sendMessage(message);

                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    }

            }

        });

        String message = "";
        while (!message.equals("/stop")) {
                message = in.readUTF();
                app.logMessage(message);
        }

    } catch (IOException e) {
        System.err.println("IO exception in connection handler!");
        System.err.println(e.getStackTrace());
    } finally {
        try {
            out.close();
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    }

    private void sendMessage(String message) throws IOException {
        out.writeUTF(message);
        out.flush();

    }       

}

【问题讨论】:

  • 类似Here 的内容可能对您来说是一个很好的解决方案。使用 BlockingQueue 在线程之间传递信息。
  • @TimHunter BlockingQueue 是否可以与作为单独应用程序运行的每个客户端一起使用?我不确定它如何转移。
  • 你给每个客户一个自己的线程让事情变得很困难。如果您没有这种设计,处理这一特定工作的线程可以一次性完成向每个客户端发送的一些工作。
  • @ElliottV4 啊,不。这仅适用于单个程序中的多个线程。对于您的情况,您只需让服务器充当所有客户的“交汇点”。他们告诉服务器他们想说什么,然后服务器将其传递给所有其他客户端。如果您的服务器使用多个线程来处理每个客户端,您只会使用 BlockingQueue。否则,一旦服务器知道该消息,它就可以将其传递给与之连接的其他人。

标签: java multithreading sockets server client


【解决方案1】:

您需要了解套接字是如何工作的。它们始终是客户端和服务器。
有两种方法可以实现您想要的:

第一个解决方案:
将适用于所有客户端的消息发送到服务器,并让服务器将消息分发给所有其他客户端。服务器需要跟踪已经连接的客户端,即存储它们的Socket


第二种解决方案:(完全不可取)
如果您想在不涉及实际服务器的情况下向网络客户端发送消息,则需要该客户端充当服务器,或者反过来。这意味着每个客户端实际上都需要监听所有其他客户端,而不仅仅是服务器。

您绝对应该使用第一个解决方案!

【讨论】:

  • 所以我需要做这样的事情吗? Client's Message -> Server Server 分发消息到 OutputStream 所有客户端通过 InputStream 获取消息
  • 那行不通。我尝试将消息从服​​务器的输入流写入服务器的输出流,就像我发送常规消息的方式一样,但客户端没有收到消息。
  • 我会通过让服务器存储其客户端(套接字)的 ArrayList 来实现这一点。然后让服务器监听所有客户端,当它收到消息时,将其转换为String。然后循环遍历 ArrayList 并将消息发送到所有存储的套接字。这应该有效。如果您仍然遇到错误,我建议您提出一个新问题,因为在 cmets 中很难找到并解决错误。
  • 现在可以使用了,非常感谢!阅读本文的任何人的解决方案:我创建了一个已连接套接字的数组列表,就像 ItzFlubby 建议的那样,然后每当服务器收到消息时我都会遍历列表并将消息发送到每个套接字的输出流。非常感谢您的帮助!
  • 很高兴能帮到你!为了让其他人清楚这解决了您的问题,请考虑通过单击复选标记来接受正确的答案!
猜你喜欢
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
  • 2014-11-20
  • 2014-08-05
  • 2018-07-14
  • 2015-08-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多