Многопользовательское приложение чата в Java - PullRequest
2 голосов
/ 05 июня 2019

Я только начал заниматься программированием сокетов, поэтому, чтобы лучше понять его, я хочу создать приложение для чата с несколькими клиентами.

Вот как я собираюсь это сделать: После запуска приложения у вас есть два варианта: создать сервер или присоединиться к серверу.

Если вы решили создать сервер, новый поток запустится и будет размещен на сервере, а затем запустится другой поток, который собирается создать нового клиента и автоматически подключиться к серверу, просто собрав его.

И тут я столкнулся со следующей проблемой. Каждый клиент может отправлять сообщения на сервер, но для того, чтобы обеспечить их синхронизацию для всех клиентов, я думал перенаправить полученные сообщения с сервера всем клиентам, как показано на следующей диаграмме. 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 голосов
/ 08 июня 2019

Я нашел это решение, которое, кажется, работает для этого сценария Первый раз мы создаем сервер:

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