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

如何使用java使聊天程序服务器向所有连接的客户端发送消息,java,networking,tcp,chat,Java,Networking,Tcp,Chat,我已经试着做了三次这个程序,每一次都有一点进展。我的程序应该是这样工作的: 客户端向服务器发送消息,然后服务器将消息发送给所有连接的客户端(包括发送消息的客户端)。当客户机收到消息时,他们会显示它 我现在面临的问题是,服务器只向发送消息的客户机发送消息,而其他客户机没有收到任何消息。我认为这是因为我接受客户的方式,或者至少与此相关 这是我目前的代码: 客户: public class Client { protected static JTextArea textArea = new

我已经试着做了三次这个程序,每一次都有一点进展。我的程序应该是这样工作的:

客户端向服务器发送消息,然后服务器将消息发送给所有连接的客户端(包括发送消息的客户端)。当客户机收到消息时,他们会显示它

我现在面临的问题是,服务器只向发送消息的客户机发送消息,而其他客户机没有收到任何消息。我认为这是因为我接受客户的方式,或者至少与此相关

这是我目前的代码:

客户:

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;
        } 
    }       
}
公共类客户端{
受保护的静态JTextArea textArea=新的JTextArea(20,30);
受保护的静态字符串sendMSG、getMSG;
公共静态void main(字符串[]args)引发IOException{
字符串hostName=args[0];
字符串Username=args[1];
布尔发送=真;
试一试(
套接字=新的套接字(主机名,1011);
PrintWriter out=新的PrintWriter(socket.getOutputStream(),true);
BufferedReader in=新的BufferedReader(新的InputStreamReader(socket.getInputStream());
) {
BufferedReader stdIn=新的BufferedReader(新的InputStreamReader(System.in));
//帧设置
JFrame=新的JFrame(“聊天客户端”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//文本区
JScrollPane scrollPane=新的JScrollPane(textArea);
//文本字段
JTextField MSGText=新的JTextField(5);
//“发送”按钮
JButton sMSGB=新JButton(“发送”);
sMSGB.setPreferredSize(新尺寸(60,30));
sMSGB.addActionListener(新ActionListener(){
已执行的公共无效操作(操作事件){
sendMSG=MSGText.getText();
MSGText.setText(“”);
out.println(“:”+sendMSG);
}
});
//面板
JPanel p=新的JPanel();
p、 setLayout((新的BoxLayout(p,BoxLayout.PAGE_轴));
p、 增加(垂直支柱箱(5));
p、 添加(滚动窗格);
p、 增加(垂直支柱箱(5));
p、 添加(MSGText);
p、 增加(垂直支柱箱(5));
p、 添加(sMSGB);
p、 增加(垂直支柱箱(5));
frame.getContentPane().add(p);
//设置帧可见
frame.pack();
frame.setVisible(true);
System.out.println(“:opened stream”);
同时(发送){
/*而((sendMSG=stdIn.readLine())!=null){
out.println(“:”+sendMSG);
}*/
而((getMSG=in.readLine())!=null){
System.out.println(getMSG);
textArea.append(getMSG+“\n”);
//发送=假;
}
}
//发送=真;
} 
}       
}
服务器:

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();
        }
    }
}
公共类服务器{
公共静态void main(字符串[]args){
try(ServerSocket-ServerSocket=newserversocket(1011)){
布尔监听=真;
边听{
Socket=serverSocket.accept();
List outs=新的CopyOnWriteArrayList();
新的ServerThread(套接字,out).start();
System.out.println(“打开的线程”);
}
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
服务器线程:

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();
        }
    }
}
public类ServerThread扩展线程{
专用终端插座;
私人最终名单;
公共服务器线程(套接字、列表){
超级(“服务器线程”);
this.socket=socket;
这个.outs=outs;
System.out.println(“openouts:+outs.size());
}
私有void sendToAll(字符串msg){
用于(打印输出:输出){
out.println(msg);
}
}
公开募捐{
试一试(
PrintWriter out=新的PrintWriter(socket.getOutputStream(),true);
BufferedReader in=新的BufferedReader(新的InputStreamReader(socket.getInputStream());
) {
System.out.println(“流打开”);
out.添加(out);
字符串getMSGs;
而((getMSGs=in.readLine())!=null){
//out.println(getMSGs);
sendToAll(getMSGs);
System.out.println(“接收和发送消息”);
}
}捕获(IOE异常){
e、 printStackTrace();
}
}
}

我希望你能帮忙。提前感谢

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

            while(listening) {
                Socket socket = serverSocket.accept();
                List<PrintWriter> outs = new CopyOnWriteArrayList<PrintWriter>();
                new ServerThread(socket, outs).start();
                System.out.println("opened thread");
            }
while(监听){
Socket=serverSocket.accept();
List outs=新的CopyOnWriteArrayList();
新的ServerThread(套接字,out).start();
System.out.println(“打开的线程”);
}
而且基本上是用空的
输出生成线程。您需要将输出流(或套接字)列表保持在循环之外,并在更新
outs
列表(当新客户端连接时)时构建一种向现有线程发送信号的方法