在 JavaFX 的客户端服务器聊天应用程序中向所有人发送消息

Send Message to All in Client Server Chat Application in JavaFX

我能够向连接到服务器的客户端发送消息,但是当

  1. 当 Client Bunny 向 Joel 发送消息(接收消息)时,反之亦然。
  2. 当Bunny第二次给Joel发消息时(没有收到消息)。

如何再次迭代哈希表循环以发送和接收消息。

服务器Class

import java.io.*; //Input and output to read and write data.
import java.net.*; //serversocket and initaddress  
import java.util.Date; //to get date
import java.util.Enumeration; //enumeration
import java.util.Hashtable; // hashtable
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javafx.application.Application; //
import javafx.application.Platform; //platformrun later to append text
import javafx.event.EventHandler; // on click actions
import javafx.geometry.Insets; //insets
import javafx.geometry.Pos; //position
import javafx.scene.Scene; //scene
import javafx.scene.control.TextArea; //textarea
import javafx.scene.layout.StackPane; //stackpane
import javafx.stage.Stage; //stage
import javafx.stage.WindowEvent; //event close

public class Server extends Application { //class server

    static InetAddress inetAddress; //inetaddress
    private final Hashtable<Object, Object> outputStreams = new Hashtable(); //hashtable
    TextArea textarea = new TextArea(); //textarea
    static DataInputStream inputFromClient = null; //datainputstream
    static DataOutputStream outputToClient = null; //dataoutputstream
    static int clientNo = 0; //client connected
    static ServerSocket serverSocket; //server socket
    Hashtable<Object, Object> hmap = new Hashtable<>();

    @Override // Override the start method in the Application class
    public void start(Stage primaryStage) { //Stage to show everything

        StackPane root = new StackPane();        //root add all the elements
        root.setPadding(new Insets(10, 10, 10, 10)); //padding
        root.setAlignment(textarea, Pos.CENTER); //positioning textarea to center
        textarea.setMaxSize(400, 400); //maxsize of textarea
        textarea.setWrapText(true); //wraptext for the textarea

        new Thread(() -> { //thread to hold the server for the connections
            try {
                // Create a server socket
                ServerSocket serverSocket = new ServerSocket(8001); //The server creates a server socket and, once a connection to a client is established, connects to the client with a client socket.
                textarea.appendText("MultiThreadServer started at " + new Date() + '\n'); //server started with date.

                while (true) { //accept multiple connections

                    // Listen for a new connection request
                    Socket socket = serverSocket.accept(); //listening for new connection from server port.
//                    inputFromClient = new DataInputStream(socket.getInputStream());
                    outputToClient = new DataOutputStream(socket.getOutputStream()); //outputstream to output to client
                    // Increment clientNo
                    clientNo++;

                    Platform.runLater(() -> {
                        // Display the client number
                        textarea.appendText("Starting thread for client " + clientNo + " at " + new Date() + '\n');

                        // Find the client's host name, and IP address
                        InetAddress inetAddress = socket.getInetAddress();
                        textarea.appendText("Client " + clientNo + "'s host name is " + inetAddress.getHostName() + "\n");
                        textarea.appendText("Client " + clientNo + "'s IP Address is " + inetAddress.getHostAddress() + "\n");
                    });

                    HandleAClient hd = new HandleAClient(socket);
                    hmap.put(socket, outputToClient);
                    hd.start();
//                    outputStreams.put(socket, outputToClient); //using hashtable to store client socket and outputstream

                    // Create and start a new thread for the connection
//                    new HandleAClient(this, socket);
                }
            } catch (IOException ex) {
                textarea.appendText(ex + " \n");
            }
        }).start();

        root.getChildren().addAll(textarea); // add UI elements to the root
        Scene scene = new Scene(root, 450, 400); // creating scene of size 450 width and height 500

        primaryStage.setTitle("Server"); // Set the stage title
        primaryStage.setScene(scene); // Place the scene in the stage
        primaryStage.show(); // Display the stage

        primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() { //close scene
            @Override
            public void handle(WindowEvent t) {
                primaryStage.close();
                Platform.exit();
                System.exit(0);
            }
        });
    }

    // Used to get the output streams
    Enumeration getOutputStreams() {
        return outputStreams.elements();
    }

    // Used to send message to all clients
    void sendToAll(String message) {
        // Go through hashtable and send message to each output stream
        for (Enumeration e = getOutputStreams(); e.hasMoreElements();) {
            DataOutputStream dout = (DataOutputStream) e.nextElement();
            try {
                // Write message
                dout.writeUTF(message);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    class HandleAClient extends Thread {

        private Socket socket; // A connected socket
        private String text = "";

        /**
         * Construct a thread
         */
        public HandleAClient(Socket socket) throws IOException {
            this.socket = socket;
        }

        /**
         * Run a thread
         */
        public void run() {
            try {
                // Create data input stream
                inputFromClient = new DataInputStream(socket.getInputStream()); //receive input from client

                textarea.appendText(new Date() + " Connection from  " + socket + "\n");//showing connection from client

                text = inputFromClient.readUTF(); // read string or message from client

//                serversocket.sendToAll(text); 
                Set set = hmap.entrySet();
                Iterator it = set.iterator();
                while (it.hasNext()) {
                    Map.Entry entry = (Map.Entry) it.next();
                    System.out.println("key " + entry.getKey() + " : " + entry.getValue());
                    DataOutputStream dout = (DataOutputStream) entry.getValue();
                    dout.writeUTF(text);
                    dout.flush();
                }

                Platform.runLater(() -> {
                    textarea.appendText(new Date() + "         " + text + "\n");//append text
                });

            } catch (IOException e) {
                textarea.appendText("Error " + e + " \n");
                try {
                    this.socket.close(); //socket close
                } catch (IOException ex) {
                    textarea.appendText("Error " + e + "  \n");
                }
                e.printStackTrace();
            }
        }

    }

    public static void main(String[] args) { //The keyword void simply tells the compiler that main( ) does not return a value.
        launch(args);
    }
}



Client Class

import java.io.*; //Input and output to read and write data.
import java.net.*; //serversocket and initaddress  
import javafx.application.Application; //
import javafx.application.Platform; //platformrun later to append text
import javafx.event.EventHandler; // on click actions
import javafx.geometry.Insets; //insets
import javafx.geometry.Pos; //position
import javafx.scene.Scene; //scene
import javafx.scene.control.TextArea; //textarea
import javafx.scene.layout.StackPane; //stackpane
import javafx.stage.Stage; //stage
import javafx.stage.WindowEvent; //event close

import javafx.scene.control.Button; // button
import javafx.scene.control.Label; //label
import javafx.scene.control.TextField; //textfield

public class Client extends Application {

    // IO streams
    static DataOutputStream toServer = null; //datainputstream
    static DataInputStream fromServer = null; //dataoutputstream
    Label usernamelabel = new Label("Set your name :"); //set name label
    Label textarealabel = new Label("Type your message in the textarea"); //text label
    Label textlabel = new Label("Enter Text :"); //enter text
    TextField textfield = new TextField(); //textfield
    TextField namefield = new TextField(); //name field
    Button send = new Button("Send"); //sendbutton
    TextArea messagefield = new TextArea(); //textarea
    static ServerSocket serverSocket; //serversocket

    // Override the start method in the Application class
    public void start(Stage primaryStage) throws IOException {

        StackPane root = new StackPane(); //stacpane
        root.setPadding(new Insets(10, 10, 10, 10));

        StackPane.setAlignment(usernamelabel, Pos.TOP_LEFT);
        namefield.setMaxWidth(200);
        StackPane.setAlignment(namefield, Pos.TOP_CENTER);

        StackPane.setMargin(textlabel, new Insets(30, 0, 0, 0));
        StackPane.setMargin(textfield, new Insets(30, 0, 0, 0));
        StackPane.setAlignment(textlabel, Pos.TOP_LEFT);
        textfield.setMaxWidth(200);
        StackPane.setAlignment(textfield, Pos.TOP_CENTER);

        StackPane.setAlignment(send, Pos.BOTTOM_CENTER);
        messagefield.setMaxSize(450, 250);
        StackPane.setAlignment(textarealabel, Pos.BOTTOM_CENTER);
        StackPane.setMargin(textarealabel, new Insets(0, 0, 35, 0));
        StackPane.setAlignment(messagefield, Pos.CENTER);

        root.getChildren().addAll(usernamelabel, namefield, send, messagefield, textarealabel, textlabel, textfield); //adding all the UI elements

        // Create a scene and place it in the stage
        Scene scene = new Scene(root, 500, 400);
        primaryStage.setTitle("Client"); // Set the stage title
        primaryStage.setScene(scene); // Place the scene in the stage
        primaryStage.show(); // Display the stage

        send.setOnAction(e -> { //send button action
            try {
                if (namefield.getText().trim().length() == 0) { //name field is empty
                    messagefield.appendText("Name field is empty. Please enter your name\n");
                } else if (textfield.getText().trim().length() == 0) { //message field is empty
                    messagefield.appendText("Message field is empty. Please enter your message to send\n");
                }
                // Send the radius to the server
                if (namefield.getText().trim().length() > 0 && textfield.getText().trim().length() > 0) {
                    toServer.writeUTF(namefield.getText().trim() + " : " + textfield.getText().trim());
                    toServer.flush();
                }

            } catch (IOException ex) {
                messagefield.appendText(ex+"   \n");
            }
        });

        try {
            // Create a socket to connect to the server
            Socket socket = new Socket("localhost", 8001); //socket with port number to connect server

            // Create an output stream to send data to the server
            toServer = new DataOutputStream(socket.getOutputStream());
            new ReceiveMessage(socket); // send socket receieve class
//            }
        } catch (Exception ex) {
            messagefield.setText(ex.toString() + '\n');
        }

        primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() { //scene close
            @Override
            public void handle(WindowEvent t) {
                Platform.exit();
                System.exit(0);
            }
        });
    }

    class ReceiveMessage implements Runnable { //class receive message

        private final Socket socket;//socket

        public ReceiveMessage(Socket socket) { // constructor
            this.socket = socket; //socket intializes
            Thread thread = new Thread(this);
            thread.setDaemon(true);
            thread.start();
        }

        public void run() {
            try {
                fromServer = new DataInputStream(socket.getInputStream()); //to read from server
                while (true) { // to continously receieve messages
                    // Get area from the server
                    String textmessage = fromServer.readUTF(); //read message from server
                    toServer.flush(); // flush
                    Platform.runLater(() -> {
                        messagefield.appendText(textmessage + " \n"); //append to textarea
                    });
                }
            } catch (IOException e) {
                messagefield.appendText("Error " + e);
            }
        }
    }

    public static void main(String[] args) { //The keyword void simply tells the compiler that main( ) does not return a value.
        launch(args);
    }
}

服务器 class 已执行并占用客户端

客户端一已连接

客户端二连

谢谢。

我在代码中犯的错误是在客户端向服务器发送消息并在服务器连接暂停或停止后向所有连接到服务器的客户端发送消息我不知道为什么。我使用枚举方法向连接到服务器的所有客户端发送消息。这就是我解决问题的方法。希望我的回答对尝试使用线程实现客户端-服务器(多客户端)聊天应用程序的人有所帮助。

import java.io.*; 
import java.net.*; 
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration; 
import java.util.Hashtable; 
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javafx.application.Application;
import javafx.application.Platform; 
import javafx.event.EventHandler;
import javafx.geometry.Insets; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.TextArea;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage; 
import javafx.stage.WindowEvent; 

public class Server extends Application { 

    static InetAddress inetAddress; 
    private final Hashtable<Object, Object> outputStreams = new Hashtable(); 
    TextArea textarea = new TextArea(); 
    static int clientNo = 0; 
    static ServerSocket serverSocket; 
    Hashtable<Object, Object> hmap = new Hashtable<>();
    ArrayList<Object> clients = new ArrayList<Object>();


    public void start(Stage primaryStage) {

        StackPane root = new StackPane(); 
        root.setPadding(new Insets(10, 10, 10, 10)); 
        root.setAlignment(textarea, Pos.CENTER);
        textarea.setMaxSize(400, 400); 
        textarea.setWrapText(true); 

        root.getChildren().addAll(textarea); 
        Scene scene = new Scene(root, 450, 400); 

        primaryStage.setTitle("Server"); 
        primaryStage.setScene(scene);
        primaryStage.show(); // Display the stage

        primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() { 
            @Override
            public void handle(WindowEvent t) {
                primaryStage.close();
                Platform.exit();
                System.exit(0);
            }
        });

        new Thread(() -> {
            listen();
        }).start();
    }

    private void listen() {

        try {
            // Create a server socket
            serverSocket = new ServerSocket(8001); 
            textarea.appendText("MultiThreadServer started at " + new Date() + '\n'); 

            while (true) { 

                Socket socket = serverSocket.accept(); 
      inputFromClient = new DataInputStream(socket.getInputStream());
                DataOutputStream outputToClient = new DataOutputStream(socket.getOutputStream()); 
                clientNo++;

                Platform.runLater(() -> {

                    textarea.appendText("Starting thread for client " + clientNo + " at " + new Date() + '\n');


                    InetAddress inetAddress = socket.getInetAddress();
                    textarea.appendText("Client " + clientNo + "'s host name is " + inetAddress.getHostName() + "\n");
                    textarea.appendText("Client " + clientNo + "'s IP Address is " + inetAddress.getHostAddress() + "\n");
                });

                hmap.put(socket, outputToClient);
                new HandleAClient(socket);

            }
        } catch (IOException ex) {
            textarea.appendText(ex + " \n");
        }

    }


    Enumeration getOutputStreams() {
        return hmap.elements();
    }


    void sendToAll(String message) {

        for (Enumeration e = getOutputStreams(); e.hasMoreElements();) {
            DataOutputStream dout = (DataOutputStream) e.nextElement();
            try {

                dout.writeUTF(message);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    void All(String text) throws IOException {
        Set set = hmap.entrySet();
        Iterator it = set.iterator();
        System.out.println("Text " + text);
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            System.out.println("key " + entry.getKey() + " : " + entry.getValue());
            DataOutputStream dout = (DataOutputStream) entry.getValue();
            dout.writeUTF(text);
            dout.flush();
        }
    }

    class HandleAClient extends Thread {

        private final Socket socket; // A connected socket
        private String text = "";

        /**
         * Construct a thread
         */
        public HandleAClient(Socket socket) throws IOException {
            this.socket = socket;
            start();
        }

        /**
         * Run a thread
         */
        public void run() {
            try {

                DataInputStream inputFromClient = new DataInputStream(socket.getInputStream()); //receive input from client
                while (true) {

                    textarea.appendText(new Date() + " Connection from  " + socket + "\n");

                    text = inputFromClient.readUTF(); 

             serversocket.sendToAll(text); 
                    All(text);

                    Platform.runLater(() -> {
                        textarea.appendText(new Date() + "         " + text + "\n");
                    });
                }

            } catch (IOException e) {
                textarea.appendText("Error " + e + " \n");
                try {
                    this.socket.close();
                } catch (IOException ex) {
                    textarea.appendText("Error " + e + "  \n");
                }
                e.printStackTrace();
            }
        }

    }

    public static void main(String[] args) { //The keyword void simply tells the compiler that main( ) does not return a value.
        launch(args);
    }
}