多客户端聊天应用程序 java

Multi client chat application In java

我刚开始接触套接字编程,所以为了加深对它的理解,我想构建一个多客户端聊天应用程序。

我打算这样做的方式如下: 应用程序启动后,您有两个选择:创建服务器或加入服务器。

如果您选择创建服务器,将启动一个新线程并托管服务器,然后将启动另一个线程,该线程将创建一个新客户端并自动连接到刚刚构建的服务器。

在这里我遇到了以下问题。 每个客户端都可以向服务器发送消息,但为了使所有客户端的消息保持同步,我正在考虑将检索到的消息从服务器重定向到所有客户端,如下图所示。

问题是,当我尝试在客户端和服务器上监听和发送时,我收到了这个错误。

java.net.SocketException: Connection reset
    at java.base/java.net.SocketInputStream.read(SocketInputStream.java:186)
    at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
    at java.base/java.net.SocketInputStream.read(SocketInputStream.java:200)
    at java.base/java.io.DataInputStream.readUnsignedShort(DataInputStream.java:342)
    at java.base/java.io.DataInputStream.readUTF(DataInputStream.java:594)
    at java.base/java.io.DataInputStream.readUTF(DataInputStream.java:569)
    at parctice.Server.lambda$main[=11=](Server.java:32)
    at java.base/java.lang.Thread.run(Thread.java:835)

这是我的服务器:

int port = 4444;

        try {
            ServerSocket serverSocket = new ServerSocket(port);
            System.out.println("server starts port = " + serverSocket.getLocalSocketAddress());


            while(true){
                Socket socket = serverSocket.accept();
                System.out.println("accepts : " + socket.getRemoteSocketAddress());

                DataInputStream in = new DataInputStream(socket.getInputStream());
                DataOutputStream out = new DataOutputStream(socket.getOutputStream());


                String[] message = {""};

                new Thread(() -> {
                    try {
                        while(in.available() > 0){
                            System.out.println("SERVER > " + in.readUTF());
                            message[0] = in.readUTF();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }).start();

                System.err.println(message[0]);
                try {
                    out.writeUTF(message[0] + "REDIRECTED MESSAGE");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

和我的客户:

int portNumber = 4444;
System.out.println("CLIENT >  Trying to connect to the server...");
try {
    Socket socket = new Socket("localhost", portNumber);

    DataInputStream in = new DataInputStream(socket.getInputStream());
    DataOutputStream out = new DataOutputStream(socket.getOutputStream());


    new Thread(() -> {
        try {
            while(in.available() > 0){
                System.out.println("SERVER > " + in.readUTF());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).start();


    try {
        out.writeUTF("test");
    } catch (IOException e) {
        e.printStackTrace();
    }

} catch (IOException e) {
    e.printStackTrace();
}

最后我想问问你们,你们是否认为我尝试使用的逻辑是正确的,如果不是,请告诉我哪里出了问题,如果可能的话,你们能解释一下为什么我是无法同时在客户端和服务器上收听和发送?因为当我尝试通过客户端发送数据并在服务器上检索它时它工作得很好,但我想完成双向通信。

我发现这个解决方案似乎适用于这种情况 第一次创建服务器:

private List<ClientThread> clients; // or "protected static List<ClientThread> clients;"


public List<ClientThread> getClients(){
    return clients;
}
    private void startServer(){
        clients = new ArrayList<ClientThread>();
        try {
            serverSocket = new ServerSocket(PORT);
            System.out.println("SERVER ON");
            System.out.println("SERVER > Waiting for connections...");


//            ACCEPT ALL CONNECTIONS
            while (true){
                try {
                    Socket socket = serverSocket.accept();
                    System.out.println("SERVER > New connection: " + socket.getRemoteSocketAddress());
                    ClientThread client = new ClientThread(this, socket);
                    Thread thread = new Thread(client);
                    thread.start();
                    clients.add(client);
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("SERVER > Accept failed");
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

然后我们为每个客户端创建一个新线程

public class ClientThread implements Runnable {

    private Socket socket;
    private Server server;
    private String clientName;

    public String getClientName() {
        return clientName;
    }

    public void setClientName(String clientName) {
        this.clientName = clientName;
    }

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    public ClientThread(Server server, Socket socket) {
        this.server = server;
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            DataInputStream in = new DataInputStream(socket.getInputStream());
            DataOutputStream out = new DataOutputStream(socket.getOutputStream());

            out.writeUTF("HI FROM SERVER");
            while (!socket.isClosed()) {
                try {
                    if (in.available() > 0) {
                        String input = in.readUTF();
                        // UNCOMMENT TO READ ON SERVER
                        // System.out.println("SERVER > " + input);
                        for (ClientThread thatClient : server.getClients()){
                            DataOutputStream outputParticularClient = new DataOutputStream(thatClient.getSocket().getOutputStream());
                            outputParticularClient.writeUTF(input + " GOT FROM SERVER");
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户:

    public void createClient(){
        try {
            socket = new Socket("localhost", portNumber);
//            socket = new Socket(getHost(), portNumber);

            DataInputStream in = new DataInputStream(socket.getInputStream());
            new Thread(()->{
                while(!socket.isClosed()){
                    try {
                        if (in.available() > 0){
                            String input = in.readUTF();
                            System.out.println(getUserName() + " > " + input);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }