如何使用套接字将数据从服务器发送到多个客户端?

Rus*_*mov 3 java sockets client multithreading server

我有简单的服务器-客户端程序:

public class Server extends Thread {
    private ServerSocket server;

    public Server(int port) {
        try {
            this.server = new ServerSocket(port);
            System.out.println("New server initialized!");
            this.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void run() {
        while (true) {
            try {
                Socket client = server.accept();
                System.out.println(client.getInetAddress().getHostName()
                        + " connected");
                new ServerHandler(client);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

服务器处理程序必须在流中发送消息:

public class ServerHandler extends Thread {
    protected Socket client;
    protected String userInput;
    protected PrintWriter out;
    protected BufferedReader console;

    public ServerHandler(Socket client) {
        this.client = client;
        this.userInput = null;
        this.start();
    }

    public void run() {
        System.out.println("New Communication Thread Started");
        System.out.println("Enter message:");
        try {
            this.out = new PrintWriter(client.getOutputStream(), true);
            this.console = new BufferedReader(new InputStreamReader(System.in));
            while ((this.userInput = console.readLine()) != null) {
                this.out.println(userInput);
            }               
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

客户端收到该消息:

public class Client {
    protected Socket client;
    protected BufferedReader in;

    public Client(String hostName, int ip) {
        try {
            this.client = new Socket(hostName, ip);
            this.in = new BufferedReader(new InputStreamReader(
                    this.client.getInputStream()));
            String buffer = null;
            while ((buffer = in.readLine()) != null) {
                System.out.println(buffer);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它仅适用于一个客户端,但是当我启动新客户端时,出现了从服务器接收消息的问题。我究竟做错了什么?

Rus*_*mov 6

我找到了答案:

public class Server extends Thread {
    private ServerSocket server;
    protected List<ClientHandler> clients;

    public Server(int port) {
        try {
            this.server = new ServerSocket(port);
            System.out.println("New server initialized!");
            clients = Collections
                    .synchronizedList(new ArrayList<ClientHandler>());
            this.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void run() {
        while (true) {
            try {
                Socket client = server.accept();
                System.out.println(client.getInetAddress().getHostName()
                        + " connected");
                ClientHandler newClient = new ClientHandler(client);
                clients.add(newClient);
                new SendMessage(clients);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用ClientHandler代替Serverhandler类:

public class ClientHandler {
    protected Socket client;
    protected PrintWriter out;

    public ClientHandler(Socket client) {
        this.client = client;
        try {
            this.out = new PrintWriter(client.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

可以将线程添加到Client类,但是没有它可以正常工作。我想是因为当主方法调用新线程时会自动创建:

public class Client {
    protected Socket client;
    protected BufferedReader in;

    public Client(String hostName, int ip) {
        try {
            this.client = new Socket(hostName, ip);
            this.in = new BufferedReader(new InputStreamReader(
                    this.client.getInputStream()));
            String buffer = null;
            while ((buffer = in.readLine()) != null) {
                System.out.println(buffer);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }       
}
Run Code Online (Sandbox Code Playgroud)

将数据发送到客户端的类:

 public class SendMessage extends Thread {
        protected List<ClientHandler> clients;
        protected String userInput;
        protected BufferedReader console;

        public SendMessage(List<ClientHandler> clients) {
            this.clients = clients;
            this.userInput = null;
            this.start();
        }

        public void run() {
            System.out.println("New Communication Thread Started");
            if (clients.size() == 1) {
                System.out.println("Enter message:");
            }
            try {
                if (clients.size() > 0) {
                    this.console = new BufferedReader(new InputStreamReader(
                            System.in));
                    while ((this.userInput = console.readLine()) != null) {
                        if (userInput != null & userInput.length() > 0) {
                            for (ClientHandler client : clients) {
                                client.out.println(userInput);
                                client.out.flush();
                            Thread.currentThread();
                            Thread.sleep(1 * 1000);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在可以了!刷新数据后需要使SendMessage线程休眠。服务器启动器主要:

public static void main(String[] args) {
new Server(1200);
}
Run Code Online (Sandbox Code Playgroud)

客户入门的主要内容:

public static void main(String[] args) {
new Client("127.233.0.1", 1200);
}
Run Code Online (Sandbox Code Playgroud)