Java 编写点对点聊天系统时遇到问题

Java 编写点对点聊天系统时遇到问题,java,multithreading,sockets,Java,Multithreading,Sockets,这是我得到的问题陈述: 设计一个协议,其中一个服务器负责匹配两个chatt客户端。服务器在TCP端口上侦听即将到来的连接。 如果尚未将任何客户端连接到要配对的服务器,则服务器将接受连接的客户端,并使其等待另一个客户端。为此,它向连接客户端发送一条消息等待。接收此命令时,客户端构造另一个服务器套接字实例以侦听端口。然后,客户端向服务器发送一个MESAGE,其中包含新创建的服务器侦听的端口号。 当另一个客户端C2在C1等待时寻求与服务器的连接时,服务器通过向C2发送消息“PEER_LOC$h:$p”

这是我得到的问题陈述:

设计一个协议,其中一个服务器负责匹配两个chatt客户端。服务器在TCP端口上侦听即将到来的连接。 如果尚未将任何客户端连接到要配对的服务器,则服务器将接受连接的客户端,并使其等待另一个客户端。为此,它向连接客户端发送一条消息等待。接收此命令时,客户端构造另一个服务器套接字实例以侦听端口。然后,客户端向服务器发送一个MESAGE,其中包含新创建的服务器侦听的端口号。 当另一个客户端C2在C1等待时寻求与服务器的连接时,服务器通过向C2发送消息“PEER_LOC$h:$p”通知C2存在C1,其中$h是C1的主机名(或IP地址),而$p是C1等待的端口号。C2收到此消息后,它使用获得的信息寻找到C1的连接。客户端从用户处获取消息。然后,这两个客户端交换消息,直到任何一方发送流的末尾”(Linux中的Ctrl-D)。然后终止它们的保存。复杂的方法可能会使用多个线程、超时等,在这个问题中不需要

我的问题是将两个客户端连接到我的服务器。我运行我的服务器程序,然后运行另外两个客户机类,它们彼此重复,只是名称不同。我只能连接到其中一个,而另一个似乎永远在等待

这些是我的课程,我运行

服务器:

package chatserver2;

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
   // import all the class that you will need for functionailty

// extends jframe to develop gui's in java
public class Server {

    private static ObjectOutputStream output; // stream data out
    private static ObjectInputStream input; // stream data in
    private static ServerSocket server;
    private static Socket connection; // socket means set up connetion between 2 computers

    private static int n;

//Constructor
    public static void main(String[] args) throws IOException {

        Server obj = new Server();
        obj.RunServer();

        try {
            while (true) {

                Handler obj2 = new Handler();

                obj2.start();
                System.out.println("Accepted connection from "
                        + connection.getInetAddress() + " at port "
                        + connection.getPort());

                n++;
                System.out.println("Count " + n);
            }
        } finally {
            connection.close();
        }

    }

    public Server() {

    }

// run the server after gui created
    public void RunServer() {

        try {
            server = new ServerSocket(6789); // 1st number is port number where the application is located on the server, 2nd number is the amount of people aloud to connect
            while (true) {

                try {
                    waitForConnection(); // wait for a connection between 2 computers 
                    setupStreams();  // set up a stream connection between 2 computers to communicate
                    whileChatting();  // send message to each other
                    // connect with someone and have a conversation
                } catch (EOFException eofException) {

                }
            }
        } catch (IOException ioException) {

            ioException.printStackTrace();
        }
    }

//Wait for a connection then display connection information
    private void waitForConnection() {

        try {
            connection = server.accept();
        } catch (IOException ioexception) {

            ioexception.printStackTrace();
        }

    }
    // stream function to send and recive data

    private void setupStreams() throws IOException {

        output = new ObjectOutputStream(connection.getOutputStream()); // set up pathway to send data out
        output.flush(); // move data away from your machine
        input = new ObjectInputStream(connection.getInputStream()); // set up pathway to allow data in

    }

// this code while run during chat conversions
    private void whileChatting() throws IOException {

        String message = "WAIT ";
        sendMessage(message);

        do {

            try {

                message = (String) input.readObject(); // stores input object message in a string variable

                System.out.println("Message from Client " + message);
            } catch (ClassNotFoundException classnotfoundException) {

            }
        } while (!message.equals("CLIENT - END"));// if user types end program stops

    }

    private void closeChat() {

        try {

            output.close();
            input.close();
            connection.close();

        } catch (IOException ioexception) {

            ioexception.printStackTrace();
        }
    }

// send message to the client
    private void sendMessage(String message) {

        try {

            output.writeObject(message);
            output.flush();

            System.out.println("Message to client " + message);

        } catch (IOException ioexception) {

        }

    }

    public static class Handler extends Thread {

        private Socket connection;

        public Handler() {

            String message = "WAIT";

        }

        public void run() {

            System.out.println("Connect" + Server.connection);
            while (true) {

                try {
                    waitForConnection();
                    setupStreams();
                    whileChatting();
                } catch (IOException ex) {
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }

            }

        }

        private void waitForConnection() {

            System.out.println("server" + server);
            try {
                connection = server.accept();
            } catch (IOException ioexception) {

                ioexception.printStackTrace();
            }
            System.out.println("Connection" + connection);

        }

        private void setupStreams() throws IOException {

            output = new ObjectOutputStream(connection.getOutputStream()); // set up pathway to send data out
            output.flush(); // move data away from your machine
            input = new ObjectInputStream(connection.getInputStream()); // set up pathway to allow data in

        }

        private void whileChatting() throws IOException {

            String message = " You are now connected ";
            sendMessage(message);

            do {

                try {

                    message = (String) input.readObject();

                } catch (ClassNotFoundException classnotfoundException) {

                }
            } while (!message.equals("CLIENT - END"));

        }

        private void closeChat() {

            try {

                output.close();
                input.close();
                connection.close();

            } catch (IOException ioexception) {

                ioexception.printStackTrace();
            }
        }

        static private void sendMessage(String message) {

            try {

                output.writeObject(message);
                output.flush();

            } catch (IOException ioexception) {

            }

        }

    }
}
和一个重复的客户端类别C1或C2:

package chatserver2;

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
   // import all the class that you will need for functionailty

// extends jframe to develop gui's in java
public class Client1 extends JFrame {

    private JTextField userInput; // 
    private JTextArea theChatWindow; //
    private ObjectOutputStream output; // stream data out
    private ObjectInputStream input; // stream data in

    private Socket connection; // socket means set up connetion between 2 computers

//Constructor
    public Client1() {

    }

// run the server after gui created
    public void RunClient() {

        try {
            connection = new Socket("localhost", 6789);// 1st number is port number where the application is located on the server, 2nd number is the amount of people aloud to connect
            while (true) {

                try {
                    // wait for a connection between 2 computers 
                    setupStreams();  // set up a stream connection between 2 computers to communicate
                    whileChatting();  // send message to each other
                    // connect with someone and have a conversation
                } catch (EOFException eofException) {

                } finally {

                    closeChat();
                }
            }
        } catch (IOException ioException) {

            ioException.printStackTrace();
        }
    }

//Wait for a connection then display connection information
    // stream function to send and recive data
    private void setupStreams() throws IOException {

        output = new ObjectOutputStream(connection.getOutputStream()); // set up pathway to send data out
        output.flush(); // move data away from your machine
        input = new ObjectInputStream(connection.getInputStream()); // set up pathway to allow data in

    }

// this code while run during chat conversions
    private void whileChatting() throws IOException {

        String message = "";

        do {
            // have conversion while the client does not type end
            try {

                message = (String) input.readObject(); // stores input object message in a string variable
                System.out.println("message " + message);
                if (message.equals("WAIT")) {
                    ServerSocket server2 = new ServerSocket(5000);
                    System.out.println("Hello");
                    message = "5000";
                    sendMessage(message);

                }
                System.out.println("From server " + message);

            } catch (ClassNotFoundException classnotfoundException) {

            }
        } while (!message.equals("CLIENT - END"));// if user types end program stops

    }

    private void closeChat() {

        try {

            output.close(); // close output stream
            input.close(); // close input stream
            connection.close(); // close the main socket connection

        } catch (IOException ioexception) {

            ioexception.printStackTrace();
        }
    }

// send message to the client
    private void sendMessage(String message) {

        try {

            output.writeObject(" - " + message);
            output.flush(); // send all data out

        } catch (IOException ioexception) {

            theChatWindow.append("\n ERROR: Message cant send");
        }

    }

//
//
    public static void main(String[] args) {
        Client1 obj = new Client1();
        obj.RunClient();
    }

}
我可以连接到我运行的第一个客户端,第二个客户端将永远等待。
如果您有任何建议或意见,我们将不胜感激。

您正在阻止服务器循环。您应该为客户端的每个连接启动新线程。我会在
RunServer
方法中将
waitForConnection()
与服务器循环中的下游代码分离。因此,您的while循环应该如下所示:

public static void RunClient() {
    ...
        while (true) {
            try {
                final Server srv = waitForConnection(); // wait for a connection between 2 computers 
                new Thread(new Runnable() {
                    public void run() {
                        try {
                            srv.setupStreams();  // set up a stream connection between 2 computers to communicate
                            srv.whileChatting();  // send message to each other
                            // connect with someone and have a conversation
                        } catch (EOFException ex) {
                            // ex.printStackTrace();
                        }
                    }
                }).start();
            } catch (EOFException eofException) {

            }
        }
在这种情况下,您必须为每个客户端创建服务器实例,并且您的服务器声明应包含与客户端相关的非静态道具,如:

public class Server {
    private ObjectOutputStream output; // stream data out
    private ObjectInputStream input; // stream data in
    private static ServerSocket server;
    private Socket connection; // socket means set up connetion between 2 computers
...
服务器的创建应该在
waitForConnection()内部进行,比如:

private static Server waitForConnection() {
    try {
        Socket connection = server.accept();
        return new Server(connection);
    } catch (IOException ioexception) {
        ioexception.printStackTrace();
    }
}

这不是唯一的方法。您可以保留负责在同一实例中运行主循环的服务器类。但在本例中,我将创建一些与来自特定客户端的连接(连接、输入、输出)相关的附加类处理属性。

您正在阻止服务器循环。您应该为客户端的每个连接启动新线程。我会在
RunServer
方法中将
waitForConnection()
与服务器循环中的下游代码分离。因此,您的while循环应该如下所示:

public static void RunClient() {
    ...
        while (true) {
            try {
                final Server srv = waitForConnection(); // wait for a connection between 2 computers 
                new Thread(new Runnable() {
                    public void run() {
                        try {
                            srv.setupStreams();  // set up a stream connection between 2 computers to communicate
                            srv.whileChatting();  // send message to each other
                            // connect with someone and have a conversation
                        } catch (EOFException ex) {
                            // ex.printStackTrace();
                        }
                    }
                }).start();
            } catch (EOFException eofException) {

            }
        }
在这种情况下,您必须为每个客户端创建服务器实例,并且您的服务器声明应包含与客户端相关的非静态道具,如:

public class Server {
    private ObjectOutputStream output; // stream data out
    private ObjectInputStream input; // stream data in
    private static ServerSocket server;
    private Socket connection; // socket means set up connetion between 2 computers
...
服务器的创建应该在
waitForConnection()内部进行,比如:

private static Server waitForConnection() {
    try {
        Socket connection = server.accept();
        return new Server(connection);
    } catch (IOException ioexception) {
        ioexception.printStackTrace();
    }
}

这不是唯一的方法。您可以保留负责在同一实例中运行主循环的服务器类。但在本例中,我将创建一些与特定客户机的连接(连接、输入、输出)相关的附加类处理属性。

这可能有助于您理解其本质,也可能没有,我真的不知道


这可能有助于你把它带到本质上来,也可能没有,我真的不知道


更改静态成员会破坏代码。我在main方法中引用了连接变量。您的第一个建议是,在客户端或服务器中,RunClient在客户端类中?我是否必须以任何方式更改嵌套的内部类处理程序?我很新,这是正确的方法吗?更改静态成员会破坏我的代码。我在main方法中引用了连接变量。您的第一个建议是,在客户端或服务器中,RunClient在客户端类中?我是否必须以任何方式更改嵌套的内部类处理程序?我很新,这是正确的方法吗?主类看起来会是什么样?我必须更改这么多。在我的服务器类中,我有一个内部类,这是必要的吗?主类看起来会是什么样子?我必须改变这么多。在我的服务器类中,我有一个内部类,这是必要的吗?