проблема с подключением нескольких клиентов к серверу - PullRequest
0 голосов
/ 29 июня 2019

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

класс сервера:

public class Server implements Serializable{

    // [..]

    public void serverConnect() throws IOException, ClassNotFoundException
    {
        listener = new ServerSocket(9090);

        System.out.println("Server is running...");
        while (true)
        {
            System.out.println("Waiting ...");
            socket=listener.accept();
            for (Socket socket:socketList.keySet())
            {
                if (this.socket==socket)
                {
                checkSocket=false;
                }
            }
            if (checkSocket)
            {
            socketList.put(socket,socketNumber);
            System.out.println("Client is connected");
            inputReader = new InputStreamReader(socket.getInputStream());
            reader = new BufferedReader(inputReader);

            user = reader.readLine();
            Server.userList.add(user);
            socketNumber++;
            }
            checkSocket=true;
            }
    }
}

класс клиента:

public class Client {
    public Client() {
    }

    public void clientConnect() throws UnknownHostException, IOException {
        System.out.println("enter your username");
        Scanner scanner = new Scanner(System.in);

        String msg = scanner.nextLine();
        Socket socket = new Socket("localhost", 9090);
        PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
            writer.println(msg);
    }

}

1 Ответ

0 голосов
/ 29 июня 2019

В принципе у вас есть работа однопоточного сервера (что означает, что он может принимать только одно клиентское соединение одновременно).Основная проблема заключается в том, что вы слишком усложнили способ получения соединения.

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

    public void serverConnect() throws IOException {
        listener = new ServerSocket(9090);
        System.out.println("Server is running...");

        while (true) {
            System.out.println("Waiting ...");
            Socket socket = listener.accept();

            try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                String user = reader.readLine();
                Server.userList.add(user);
            } catch (IOException ignore) {
            } finally {
                socket.close();  
            }
        }
    }

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

В дополнение к этому вытакже хочу обернуть код внутри цикла while блоком try / catch, чтобы исключить завершение работы сервера.

Как я уже упоминал во вводном абзаце, этот код работает как однопоточный сервер и может отвечать толькона один запрос за раз.Если вы хотите принимать и обрабатывать несколько запросов, вам нужно создать новый поток для обработки ответа.Я бы порекомендовал построить ваш код, как показано ниже, но для краткости вы можете сделать что-то вроде следующего:

    public void serverConnect() throws IOException {
        int MAX_WORKERS = 100;
        ExecutorService service = Executors.newFixedThreadPool(MAX_WORKERS);
        ServerSocket listener = new ServerSocket(9090);

        System.out.println("Server is running...");
        while (true) {
            System.out.println("Waiting ...");
            Socket socket = listener.accept();

            service.submit(() -> {
                System.out.println("Client is connected");
                try {
                    try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                        String user = reader.readLine();
                        Server.userList.add(user);
                    } finally {
                        socket.close();
                    }
                } catch (Throwable ignore) {
                }
            });
        }
    }

Итак, все, что происходит выше, это то, что мы создаем пул потоков из 100 потоков, используя ExecutorService.Теоретически это означает, что мы можем принять 100 одновременных соединений.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...