Java中的多客户端聊天应用程序

时间:2019-06-05 04:15:41

标签: java sockets client-server chat serversocket

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

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

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

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

问题是,当我尝试在客户端和服务器上进行监听和发送时,会出现此错误。

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$0(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();
}

最后,我想问大家,您是否认为我尝试使用的逻辑是正确的逻辑,如果不正确,请让我知道出了什么问题,如果可以,您还可以向我解释为什么我不是能够在客户端和服务器上侦听和发送?因为当我尝试通过客户端发送数据并在服务器上检索数据时,它可以正常工作,但是我想通过两种方式完成通信。

1 个答案:

答案 0 :(得分:0)

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

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();
        }
    }