如何使聊天程序服务器向Java中的所有已连接客户端发送消息

时间:2019-09-03 14:53:55

标签: java networking tcp chat

我已经尝试过使该程序每次都进行三遍,以使程序更进一步。我的程序应该像这样工作:

客户端将消息发送到服务器,然后服务器将消息发送到所有连接的客户端(包括发送消息的客户端)。客户端收到消息后,便显示该消息。

我现在面临的问题是服务器仅将消息发送给发送该消息的客户端,而其他客户端什么也没收到。我认为这种情况的发生是因为我接受客户的方式,或者至少某种程度上与此相关。

这是我当前的代码:

客户:

public class Client {

    protected static JTextArea textArea = new JTextArea(20, 30);
    protected static String sendMSG, getMSG;

    public static void main(String[] args) throws IOException {
        String hostName = args[0];
        String Username = args[1];
        boolean sending = true;

        try (
            Socket socket = new Socket(hostName, 1011);
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        ) {
            BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

            //frame setup
            JFrame frame = new JFrame("chat client");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            //text area
            JScrollPane scrollPane = new JScrollPane(textArea);

            //text field
            JTextField MSGText = new JTextField(5);

            //"send" button
            JButton sMSGB = new JButton("send");
            sMSGB.setPreferredSize(new Dimension(60, 30));
            sMSGB.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent event) {
                    sendMSG = MSGText.getText();
                    MSGText.setText("");
                    out.println("<" + Username + ">: " + sendMSG);
                }

            });

            //panel
            JPanel p = new JPanel();
            p.setLayout((new BoxLayout(p, BoxLayout.PAGE_AXIS)));
            p.add(Box.createVerticalStrut(5));
            p.add(scrollPane);
            p.add(Box.createVerticalStrut(5));
            p.add(MSGText);
            p.add(Box.createVerticalStrut(5));
            p.add(sMSGB);
            p.add(Box.createVerticalStrut(5));
            frame.getContentPane().add(p);

            //set frame visible
            frame.pack();
            frame.setVisible(true);

            System.out.println("<Client>: opened stream");

            while(sending) {

                /*while((sendMSG = stdIn.readLine()) != null) {
                    out.println("<" + Username + ">: " + sendMSG);
                }*/

                while((getMSG = in.readLine()) != null) {
                    System.out.println(getMSG);
                    textArea.append(getMSG + "\n");
                    //sending = false;
                }
            }
            //sending = true;
        } 
    }       
}

服务器:

public class Server {

    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(1011)) {
            boolean listening = true;
            while(listening) {
                Socket socket = serverSocket.accept();
                List<PrintWriter> outs = new CopyOnWriteArrayList<PrintWriter>();
                new ServerThread(socket, outs).start();
                System.out.println("opened thread");
            }

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

ServerThread:

public class ServerThread extends Thread {

    private final Socket socket;
    private final List<PrintWriter> outs;

    public ServerThread(Socket socket, List<PrintWriter> outs) {
        super("ServerThread");
        this.socket  = socket;
        this.outs = outs;
        System.out.println("Opened outs: " + outs.size());
    }

    private void sendToAll(String msg) {
        for(PrintWriter out: outs) {
            out.println(msg);
        }

    }

    public void run() {
        try (
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        ) {
            System.out.println("stream opened");
            outs.add(out);
            String getMSGs;

            while((getMSGs = in.readLine()) != null) {
                //out.println(getMSGs);
                sendToAll(getMSGs);
                System.out.println("msg received and sent");
            }

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

希望您能提供帮助。预先感谢

1 个答案:

答案 0 :(得分:0)

每次新客户端连接时,您都将重新初始化outs

            while(listening) {
                Socket socket = serverSocket.accept();
                List<PrintWriter> outs = new CopyOnWriteArrayList<PrintWriter>();
                new ServerThread(socket, outs).start();
                System.out.println("opened thread");
            }

,并且基本上生成带有空outs的线程。您需要将输出流(或套接字)的列表保留在循环之外,并构建一种在更新outs列表时(当有新的客户端连接时)发信号通知已经存在的线程的方法。