Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
具有两个并发用户的Java UDP聊天应用程序_Java_Multithreading_Udp_Chat_Datagram - Fatal编程技术网

具有两个并发用户的Java UDP聊天应用程序

具有两个并发用户的Java UDP聊天应用程序,java,multithreading,udp,chat,datagram,Java,Multithreading,Udp,Chat,Datagram,我正在尝试实现一个聊天应用程序,其中两个用户(客户端)可以相互发送和接收消息。我有两个类(服务器和客户端),在某些情况下可以在客户端之间成功地发送消息。我现在对这个项目有两个问题 第一个问题是,仅当以下步骤按此确切顺序执行时,消息才会成功传递: 启动服务器类的一个实例,然后启动客户机类的两个实例 输入其中一个客户端的用户名(从此处称为client1) 输入另一个客户端的用户名(从此处称为客户端2) 从连接到服务器的第一个客户端(客户端1)发送消息 从连接到服务器的第二个客户端(client2)发

我正在尝试实现一个聊天应用程序,其中两个用户(客户端)可以相互发送和接收消息。我有两个类(服务器和客户端),在某些情况下可以在客户端之间成功地发送消息。我现在对这个项目有两个问题

第一个问题是,仅当以下步骤按此确切顺序执行时,消息才会成功传递:

  • 启动服务器类的一个实例,然后启动客户机类的两个实例
  • 输入其中一个客户端的用户名(从此处称为client1)
  • 输入另一个客户端的用户名(从此处称为客户端2)
  • 从连接到服务器的第一个客户端(客户端1)发送消息
  • 从连接到服务器的第二个客户端(client2)发送消息
  • 继续对话,直到任一客户端发送“通信结束”
  • 如果第5步和第6步被切换,那么第二个客户机在第一个客户机之前发送一条消息,那么第一个客户机永远不会收到该消息。所有后续消息都已正确传递,但我希望无论哪个客户端发起对话,都能传递第一条消息

    第二个问题是“通信结束”字符串。如果任一客户端以消息形式发送“通信结束”,则服务器以及两个客户端都应显示“[Username]已断开连接”,然后两个客户端都应终止。服务器应继续运行,并打印初始“侦听客户端请求”消息

    现在,断开连接消息打印在两个客户机上,但两个客户机程序实际上都没有终止。服务器不会打印任何断开连接消息,也不会转到while循环的顶部。我怀疑这是因为客户端程序没有终止,所以服务器会阻塞,等待'clientThread[X].join()'。下面复制/粘贴了服务器和客户端类的代码

    服务器类的代码:

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Arrays;
    import java.util.Date;
    
    public class Server {
    
        public static final int MAXIMUM_DATAGRAM_SIZE = 255;        // Maximum size of datagram
        public static final String ECS = "End_of_Communication";        // End Communication String
    
        public static void main(String[] args) throws IOException {
    
            byte[] clientData1 = new byte[MAXIMUM_DATAGRAM_SIZE];       // Buffer for first client requesting to connect
            byte[] clientData2 = new byte[MAXIMUM_DATAGRAM_SIZE];       // Buffer for second client requesting to connect
            DatagramPacket clientPacket1 = new DatagramPacket(clientData1, clientData1.length);     // Packet for first client requesting to connect
            DatagramPacket clientPacket2 = new DatagramPacket(clientData2, clientData2.length);     // Packet for second client requesting to connect
            DatagramSocket serverSocket;        // Socket for server to listen on
            int serverPort;     // Port to start serverSocket on
            int clientPort1;
            int clientPort2;
            Runnable clientRun1;        // Runnable object for first client requesting to connect
            Runnable clientRun2;        // Runnable object for second client requesting to connect
            Thread clientThread1;       // Thread for first client requesting to connect
            Thread clientThread2;       // Thread for second client requesting to connect
            String clientAlias1;        // Alias of first client requesting to connect
            String clientAlias2;        // Alias of second client requesting to connect
    
            // Check for correct # of arguments
            if(args.length != 1)
                throw new IllegalArgumentException("Parameter(s): <Port>");
    
            // Initialize serverPort and serverSocket
            serverPort = Integer.parseInt(args[0]);
            serverSocket = new DatagramSocket(serverPort);
    
            // Loop forever and accept requests from clients
            while(true) {
    
                // Block until a client request is received, and get client alias and 
                System.out.println("[" + getTime() + "] | Listening for client requests... |");
                serverSocket.receive(clientPacket1);
                clientAlias1 = new String(clientPacket1.getData());
                clientPort1 = clientPacket1.getPort();
                System.out.println("[" + getTime() + "] | Connected to first client <" + clientAlias1 
                        + "> with socket address [" + clientPacket1.getSocketAddress() + "] |");
    
                // Block until a second client request is received, and get its alias
                serverSocket.receive(clientPacket2);
                clientAlias2 = new String(clientPacket2.getData());
                clientPort2 = clientPacket2.getPort();
                System.out.println("[" + getTime() + "] | Connected to second client <" + clientAlias2 
                        + "> with socket address [" + clientPacket2.getSocketAddress() + "] |");
    
                // Send clientAlias2 to first client
                clientData2 = clientAlias2.getBytes();
                clientPacket1.setData(clientData2);
                serverSocket.send(clientPacket1);
                // Send clientAlias1 to second client
                clientData1 = clientAlias1.getBytes();
                clientPacket2.setData(clientData1);
                serverSocket.send(clientPacket2);
    
                // Send second client's port to first client
                clientData2 = String.valueOf(clientPort2).getBytes();
                clientPacket1.setData(clientData2);
                serverSocket.send(clientPacket1);
    
                clientData1 = String.valueOf(clientPort1).getBytes();
                clientPacket2.setData(clientData1);
                serverSocket.send(clientPacket2);
    
                // Create a new thread for each client request received
                clientRun1 = new ServerThread(serverSocket, clientPacket1, clientPacket2, clientAlias1);
                clientThread1 = new Thread(clientRun1);
                clientRun2 = new ServerThread(serverSocket, clientPacket2, clientPacket1, clientAlias2);
                clientThread2 = new Thread(clientRun2);
    
                // Start each thread
                clientThread1.start();
                clientThread2.start();
    
                // Wait for threads to finish before looping again
                try{
                    clientThread1.join();
                    clientThread2.join();
                } catch(InterruptedException interrupt) {
                    System.out.println("InterruptedException: " + interrupt);
                }// End try/catch block
    
            }// End while loop
        }// End main
    
        private static String getTime() {
            DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
            Date date = new Date();
            return dateFormat.format(date);
        }
    
    }// End Server
    
    /*************************************End Server**************************************/
    /*************************************************************************************/
    /*********************************Start ServerThread**********************************/
    
    class ServerThread implements Runnable {
    
        protected DatagramSocket socket;
        protected DatagramPacket readPacket;
        protected DatagramPacket writePacket;
        protected InetAddress readAddress;
        protected InetAddress writeAddress;
        protected int readPort;
        protected int writePort;
        protected String userName;
    
        public ServerThread(DatagramSocket serverSocket, DatagramPacket readPacket, DatagramPacket writePacket, String userName) {
            this.socket = serverSocket;
            this.readPacket = readPacket;
            this.writePacket = writePacket;
            this.readAddress = readPacket.getAddress();
            this.writeAddress = writePacket.getAddress();
            this.readPort = readPacket.getPort();
            this.writePort = writePacket.getPort();
            this.userName = userName;
        }
    
        public void run() {
            try {
                String message;
                byte[] readBytes = new byte[Server.MAXIMUM_DATAGRAM_SIZE];
                byte[] writeBytes = new byte[Server.MAXIMUM_DATAGRAM_SIZE];
    
                while(true) {
    
                    // Create byte array to read data from packet into
                    readBytes = new byte[Server.MAXIMUM_DATAGRAM_SIZE];
                    readPacket = new DatagramPacket(readBytes, readBytes.length, readAddress, readPort);
    
                    // Block until packet is received, and extract its data
                    socket.receive(readPacket);
                    if(readPacket.getPort() == writePort)
                        continue;
                    message = new String(readPacket.getData());
                    if(message.equals(Server.ECS))
                        System.out.println("[" + getTime() + "] | <" + userName + "> has disconnected. |");
                    readBytes = Arrays.copyOfRange(readPacket.getData(), readPacket.getOffset(), readPacket.getOffset()+readPacket.getLength());
    
                    // Create byte array to write extracted data to
                    writeBytes = new byte[Server.MAXIMUM_DATAGRAM_SIZE];
                    writeBytes = readBytes;
                    writePacket = new DatagramPacket(writeBytes, writeBytes.length, writeAddress, writePort);
    
                    // Send the packet to its destination
                    socket.send(writePacket);
    
    
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
        }
    
        private String getTime() {
            DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
            Date date = new Date();
            return dateFormat.format(date);
        }
    
    
    }
    
    import java.io.IOException;
    导入java.net.DatagramPacket;
    导入java.net.DatagramSocket;
    导入java.net.InetAddress;
    导入java.text.DateFormat;
    导入java.text.simpleDataFormat;
    导入java.util.array;
    导入java.util.Date;
    公共类服务器{
    public static final int MAXIMUM_DATAGRAM_SIZE=255;//数据报的最大大小
    public static final String ECS=“结束通信”;//结束通信字符串
    公共静态void main(字符串[]args)引发IOException{
    byte[]clientData1=新字节[最大数据报大小];//第一个请求连接的客户端的缓冲区
    byte[]clientData2=新字节[最大数据报大小];//用于请求连接的第二个客户端的缓冲区
    DatagramPacket clientPacket1=新的DatagramPacket(clientData1,clientData1.length);//第一个请求连接的客户端的数据包
    DatagramPacket clientPacket2=新的DatagramPacket(clientData2,clientData2.length);//第二个请求连接的客户端的数据包
    DatagramSocket serverSocket;//服务器要侦听的套接字
    int serverPort;//要在其上启动serverSocket的端口
    int客户端端口1;
    int客户端端口2;
    Runnable clientRun1;//第一个请求连接的客户端的Runnable对象
    Runnable clientRun2;//请求连接的第二个客户端的Runnable对象
    Thread clientThread1;//第一个请求连接的客户端的线程
    Thread clientThread2;//第二个客户端请求连接的线程
    String clientAlias1;//请求连接的第一个客户端的别名
    String clientAlias2;//请求连接的第二个客户端的别名
    //检查参数是否正确
    如果(args.length!=1)
    抛出新的IllegalArgumentException(“参数:”);
    //初始化服务器端口和服务器套接字
    serverPort=Integer.parseInt(args[0]);
    serverSocket=新的DatagramSocket(服务器端口);
    //永远循环并接受来自客户端的请求
    while(true){
    //阻止,直到收到客户端请求,并获取客户端别名和
    System.out.println(“[”+getTime()+“]|侦听客户端请求…|”);
    serverSocket.receive(clientPacket1);
    clientAlias1=新字符串(clientPacket1.getData());
    clientPort1=clientPacket1.getPort();
    System.out.println(“[”+getTime()+“])|连接到具有套接字地址[“+clientPacket1.getSocketAddress()+”]|”的第一个客户端;
    //阻止,直到收到第二个客户端请求,并获取其别名
    serverSocket.receive(clientPacket2);
    clientAlias2=新字符串(clientPacket2.getData());
    clientPort2=clientPacket2.getPort();
    System.out.println(“[”+getTime()+“])|连接到具有套接字地址[“+clientPacket2.getSocketAddress()+”]|”的第二个客户端;
    //将clientAlias2发送到第一个客户端
    clientData2=clientAlias2.getBytes();
    clientPacket1.setData(clientData2);
    发送(clientPacket1);
    //将clientAlias1发送到第二个客户端
    clientData1=clientAlias1.getBytes();
    clientPacket2.setData(clientData1);
    发送(clientPacket2);
    //将第二个客户端的端口发送到第一个客户端
    clientData2=String.valueOf(clientPort2.getBytes();
    clientPacket1.setData(clientData2);
    发送(clientPacket1);
    clientData1=String.valueOf(clientPort1.getBytes();
    clientPacket2.setData(clientData1);
    发送(clientPacket2);
    //为收到的每个客户端请求创建一个新线程
    clientRun1=新的ServerThread(serverSocket、clientPacket1、clientPacket2、clien
    
    import java.net.DatagramSocket;
    import java.net.DatagramPacket;
    import java.net.InetAddress;
    import java.net.SocketException;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    public class Client {
    
        public static final int MAXIMUM_DATAGRAM_SIZE = 255;        // Maximum size of datagram
        public static final String ECS = "End_of_Communication";        // End Communication String
    
        public static void main(String[] args) throws IOException {
    
            BufferedReader userInput = new BufferedReader(new InputStreamReader(System.in));        // BufferedReader to get user input
            byte[] myData = new byte[MAXIMUM_DATAGRAM_SIZE];
            byte[] clientData = new byte[MAXIMUM_DATAGRAM_SIZE];
            DatagramSocket clientSocket;        // Socket for this client to connect to server
            DatagramPacket myDataPacket;
            DatagramPacket clientDataPacket;
            InetAddress serverIP;       // IP address of server
            int serverPort;     // Port that server is listening on
            int clientPort;     // Port to send messages to
            WriteThread write;      // Thread to write data to the server
            ReadThread read;        // Thread to read data from the server
            String userName;        // Alias to use for this client
            String clientName;      // Alias to use for other client
    
            // Check for correct # of arguments
            if((args.length < 1) || (args.length > 2))
                throw new IllegalArgumentException("Parameter(s): <Server> [<Port>]");
    
            // Create DatagramSocket on specified port and IP address
            serverIP = InetAddress.getByName(args[0]);
            serverPort = Integer.parseInt(args[1]);
            clientSocket = new DatagramSocket();
    
            // Connect the socket the server 
            clientSocket.connect(serverIP, serverPort);
    
            // Collect data to connect
            System.out.println("Please enter username(No Spaces): [Guest]");
            userName = userInput.readLine();
            if(userName.isEmpty())
                userName = "Guest";
    
            System.out.println("| Username set to <" + userName + ">. Sending to server... |");
            myData = userName.getBytes();
    
            // Send packet with userName to server
            myDataPacket = new DatagramPacket(myData, myData.length, serverIP, serverPort);
            clientSocket.send(myDataPacket);
    
            // Create packet to receive data about the other client from the server
            clientDataPacket = new DatagramPacket(clientData, clientData.length);
            clientDataPacket.setLength(MAXIMUM_DATAGRAM_SIZE);
            clientSocket.receive(clientDataPacket);
            clientName = new String(clientDataPacket.getData());
            clientData = new byte[MAXIMUM_DATAGRAM_SIZE];
            clientDataPacket = new DatagramPacket(clientData, clientData.length);
            clientDataPacket.setLength(MAXIMUM_DATAGRAM_SIZE);
            clientSocket.receive(clientDataPacket);
            clientPort = Integer.parseInt((new String(clientDataPacket.getData())).trim());
    
            // Create and start threads to write to and read data from the server
            write = new WriteThread(clientSocket, serverPort, userName);
            read = new ReadThread(clientSocket, clientName);
            write.start();
            read.start();
    
            // Wait for threads to finish
            try {
                write.join();
                read.join();
            } catch(InterruptedException interrupt) {
                System.out.println("InterruptedException: " + interrupt);
            }// End try/catch block
    
        }// End main
    }// End Client
    
    /*************************************End Client**************************************/
    /*************************************************************************************/
    /**********************************Start WriteThread**********************************/
    
    class WriteThread extends Thread implements Runnable {
    
        protected InetAddress serverIP;     // IP address of the server
        protected int serverPort;       // Port server is listening on
        protected DatagramSocket writeSocket;       // DatagramSocket to SEND data to server
        protected String userName;
    
        public WriteThread(DatagramSocket clientSocket, int serverPort, String userName) {
            this.writeSocket = clientSocket;
            this.serverPort = serverPort;
            this.serverIP = clientSocket.getInetAddress();
            this.userName = userName;
        }
    
        public void run() {
    
            try {
                BufferedReader userInput = new BufferedReader(new InputStreamReader(System.in));
                String writeString;
                byte[] writeBytes;
                DatagramPacket writePacket;
    
                while(true) {
                    writeBytes = new byte[Client.MAXIMUM_DATAGRAM_SIZE];
                    writeString = userInput.readLine();
                    writeBytes = writeString.getBytes();
                    writePacket = new DatagramPacket(writeBytes, writeBytes.length, serverIP, serverPort);
                    writeSocket.send(writePacket);
                    if((writeString).equals(Client.ECS))
                        break;
                    System.out.println("[" + getTime() + "]<" + userName + "> " + new String(writePacket.getData()));
                }// End while
    
                // End_of_Communiation received, print disconnect message
                System.out.println("[" + getTime() + "] | <" + userName + "> has disconnected. |");
                writeBytes = new byte[Client.MAXIMUM_DATAGRAM_SIZE];
                writeBytes = writeString.getBytes();
                writePacket = new DatagramPacket(writeBytes, writeBytes.length, serverIP, serverPort);
                writeSocket.send(writePacket);
    
            } catch (IOException ex) {
                System.out.println("IOException: " + ex);
            }// End try/catch block
        }// End run()
    
        private String getTime() {
            DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
            Date date = new Date();
            return dateFormat.format(date);
        }
    
    }// End writeThread
    
    /***********************************End WriteThread***********************************/
    /*************************************************************************************/
    /**********************************Start ReadThread***********************************/
    
    class ReadThread extends Thread implements Runnable {
    
        protected InetAddress serverIP;     // IP address of the server
        protected int serverPort;       // Port server is listening on
        protected DatagramSocket clientSocket;      // DatagramSocket to READ data to server
        protected String clientName;
    
        public ReadThread(DatagramSocket clientSocket, String clientName) throws SocketException {
            this.serverIP = clientSocket.getInetAddress();
            this.serverPort = clientSocket.getPort();
            this.clientSocket = clientSocket;
            this.clientName = clientName;
        }
    
    
        public void run() {
            try {
                byte[] readData = new byte[Server.MAXIMUM_DATAGRAM_SIZE];       // Buffer for data READ from server
                DatagramPacket readPacket;      // Packet to READ data to server
                String readMessage;     // String of the message READ from server
    
                // Loop until user requests disconnect
                while(true) {
    
    
                    // Set up datagram packet to READ from server
                    readPacket = new DatagramPacket(readData, readData.length);
    
                    // Wait for a packet to READ from server
                    clientSocket.receive(readPacket);
    
                    // Extract and print message READ from server
                    readMessage = new String(readPacket.getData(), 0, readPacket.getLength());
                    if(readMessage.equals(Client.ECS))
                        break;
                    System.out.println("[" + getTime() + "]<" + clientName + "> " + readMessage);
                }// End while
    
                // End_of_Communication received, exit
                System.out.println("[" + getTime() + "] | <" + clientName + "> has disconnected. |");
    
            } catch(IOException ex) {
                System.err.println("IOException caught: " + ex);
            }// End try/catch block
            return;
        }// End run
    
        private String getTime() {
            DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
            Date date = new Date();
            return dateFormat.format(date);
        }
    
    }// End readThread
    
    try {
        // Loop until user requests disconnect
        while(true) {
                //...bla bla...
        }// End while
    
        // End_of_Communication received, exit
        System.out.println("[" + getTime() + "] | <" + clientName + "> has disconnected. |");
    
    } catch(IOException ex) {
        System.err.println("IOException caught: " + ex);
    } finally {
        // here we want to close the socket. 
        //Even if an exception is thrown we always want to make sure that the client connection is terminated.
        clientSocket.close();
    }