从服务器向所有客户端发送消息

Sending a message from server to all clients

我正在尝试编写一个即时消息系统...最初,我是这样做的,一旦我开始工作,我将添加 GUI。

一旦客户端向服务器发送消息,服务器就应该将其显示给所有其他客户端。我怎样才能做到这一点?我一直在尝试一些事情,但它一直只显示给发送消息的客户端...

提前致谢!

服务器

import java.io.*;
import java.net.*;

class Server {
    //one per server
    static int port = 3000;
    private int backlog = 100;
    ServerSocket main;
    static DataOutputStream dataOut;
    static DataInputStream dataIn;
    static String scannerMessage;

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    static class MailServer extends Thread {
        //one per client
        static int index;
        String name = Client.name;

        public MailServer(int index, DataInputStream in, DataOutputStream out) {
            Server.dataIn = in;
            Server.dataOut = out;
            this.index = index; // thread index, one per client
        }

        public void run() {
            while (true) {
                try {
                    String receivedMessage = dataIn.readUTF();

                    //print receivedMessage to all clients

                } catch (Exception e) {
                    break;
                }
            }
        }
    }


    public Server(int port) throws Exception {
        this.main = new ServerSocket(port);
    }

    // start a serve
    public void serve() throws Exception {
        int index = 1;
        while (true) {
            Socket socket = this.main.accept();
            InputStream in = socket.getInputStream();
            OutputStream out = socket.getOutputStream();
            DataInputStream dataIn = new DataInputStream(in);
            DataOutputStream dataOut = new DataOutputStream(out);

            // handle the connection
            // keep reading using an infintite loop
            System.out.println("Handling connection to Client " + index + "...");
            (new MailServer(index, dataIn, dataOut)).start();
            index += 1; // add one every time a new client is added
        }
    }

    public static void main(String[] args) throws Exception {

        Server s = new Server(port);
        System.out.println("Serving....");
        s.serve();
    }
}

客户

import java.io.*;
import java.net.*;

class Client {

    static String hostname = "127.0.0.1";
    static int port = Server.port;
    static Socket socket;
    static String name;

    static class Sender extends Thread {
        DataOutputStream dataOut;
        public Sender(DataOutputStream dataOut) {
            this.dataOut = dataOut;
        }
        public void run() {
            while(true) {
                //get a message from the user
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
                try {
                    String message = br.readLine();
                    dataOut.writeUTF(message);
                    dataOut.flush();
                } catch(Exception e) {
                    break;
                }
            }
        }
    }

    static class Receiver extends Thread {
        DataInputStream dataIn;
        public Receiver(DataInputStream dataIn) {
            this.dataIn = dataIn;
        }
        public void run() {
            while(true) {
                try {
                    //RECEIVE A MESAGE FROM THE SERVER (ending in \n)
                    String msg = dataIn.readUTF();
                    while (msg != null) {
                        System.out.println(msg);
                        msg = dataIn.readUTF();
                    }
                } catch(Exception e) {
                    break;
                }
            }
        }
    }

    //client will require host name and the port
    public Client(String hostname, int port) throws Exception {
        socket = new Socket(hostname, port);
    }

    public void connect() throws Exception {
        InputStream in = socket.getInputStream();
        OutputStream out = socket.getOutputStream();
        DataInputStream dataIn = new DataInputStream(in);
        DataOutputStream dataOut = new DataOutputStream(out);

        //handle the connection
        System.out.println("Handling connection to server...");
        Thread sender = new Sender(dataOut);
        Thread receiver = new Receiver(dataIn);

        sender.start();
        receiver.start();

        sender.join();
        receiver.join();

        System.out.println("Client " + Server.MailServer.index);
        System.out.println("----------------------");
    }

        public static void main(String[] args) throws Exception {

            Client c = new Client(hostname, port);
            c.connect();
        }
}

更新:我创建了所有 MailServer 对象的列表,然后遍历它们以将消息发送给所有客户端,正如 JP Moresmau 所建议的那样......但现在是第一个发送内容的客户端接收所有输出。为什么是这样?我该如何解决...?谢谢,如果我的问题看起来太明显或愚蠢,我很抱歉,我仍然是一个 Java 菜鸟:(

服务器 - 已更新

package csci2020_assignment51;

import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


class Server {
    //one per server
    static int port = 3000;
    private int backlog = 100;
    ServerSocket main;
    static DataOutputStream dataOut;
    static DataInputStream dataIn;
    static String scannerMessage;

    static List<MailServer> mailServers = Collections.<MailServer>synchronizedList(new ArrayList<MailServer>());


    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    static class MailServer extends Thread {
        //one per client
        static int index;
        String name = Client.name;

        public MailServer(int index, DataInputStream in, DataOutputStream out) {        
            Server.dataIn = in;
            Server.dataOut = out;
            this.index = index; // thread index, one per client

        }

        public void run() { 
            while (true) {
                try {
                    String receivedMessage = dataIn.readUTF();
                    String outputMessage = "Client " + index + " said: " + receivedMessage;

                    //print receivedMessage to all clients
                    for (MailServer mailserver : mailServers) {
                        dataOut.writeUTF(outputMessage);
                    }

                } catch (Exception e) {
                    break;
                }
            }
        }
    }


    public Server(int port) throws Exception {
        this.main = new ServerSocket(port);
    }

    // start a serve
    public void serve() throws Exception {
        int index = 1;
        while (true) {
            Socket socket = this.main.accept();
            InputStream in = socket.getInputStream();
            OutputStream out = socket.getOutputStream();
            DataInputStream dataIn = new DataInputStream(in);
            DataOutputStream dataOut = new DataOutputStream(out);

            // handle the connection
            // keep reading using an infintite loop
            System.out.println("Handling connection to Client " + index + "...");
            MailServer mailServer = new MailServer(index, dataIn, dataOut);
            mailServer.start();
            mailServers.add(mailServer);
            dataOut.writeUTF("Client " + index);
            index += 1; // add one every time a new client is added
        }
    }

    public static void main(String[] args) throws Exception {

        Server s = new Server(port);
        System.out.println("Serving....");
        s.serve();
    }
}

拥有您创建的所有 MailServer 对象的静态列表

 static List<MailServer> servers=Collections.<MailServer>synchronizedList(new LinkedList<MailServer>);
 ...
 MailServer s=new MailServer(index, dataIn, dataOut);
 servers.add(s);
 s.start();

然后当其中一个接收到消息时循环遍历它们,并且对于所有期望的接收者,将消息写入它们的输出。

您代码中的大问题是 dataOut 和 dataIn 是唯一的!您需要将它们移动到 MailServer class。每个 MailServer 都与一个特定的客户端通信,因此需要有自己的流。

static class MailServer extends Thread {
    DataOutputStream dataOut;
    DataInputStream dataIn;

您的通知循环变为:

 for(MailServer mailServer:mailServers){
   if (mailServer!=this){
    mailServer.dataOut.writeUtf(...);
   }
 }

我也不明白您希望如何在服务器中获得 Client.name,因为客户端在另一台机器上运行...暂时摆脱它。