несколько серверов, которые также являются клиентами — общение на JAVA

#java #multithreading #sockets #server #client

#java #многопоточность #сокеты #сервер #клиент

Вопрос:

Я использую сокеты на JAVA, и у меня есть 3 сервера, которые являются клиентами одновременно. Я хочу, чтобы они обменялись некоторой информацией.

Это то, что я хочу создать: Три одноранговые машины

Входные данные должны быть примерно такими:

Сервер запущен по адресу:/172.16.2.22:8080 информация для первого, информация для второго, информация для третьего,

Сервер запущен по адресу:/172.16.2.22:8081 информация для первого, информация для второго, информация для третьего,

Сервер запущен по адресу:/172.16.2.22:8082 информация для первого, информация для второго, информация для третьего,

Но по какой-то причине он показывает только информацию о клиенте, который в настоящее время также является сервером.

Итак, я получаю этот результат:

Сервер запущен по адресу:/172.16.2.22:8080 информация для первого

Сервер запущен по адресу:/172.16.2.22:8081 информация для второго

Сервер запущен по адресу:/172.16.2.22:8082 информация для третьих

Вот как я инициирую свой код, сервер:

     private void startServer() {

    ServerSocket providerSocket = null;
    BufferedReader in = null;
    try {
        InetAddress addr = InetAddress.getByName(this.serv.getIP());
        providerSocket = new ServerSocket(this.serv.getPort(), 50, addr);
        System.out.println("ServThread started at:"   addr   ":"   this.serv.getPort());


        // create a new thread object
        Thread t = new ClientHandler(providerSocket);

        // Invoking the start() method
        t.start();


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

    }
  

Это ClientHandler, который я использую для потоков:

     class ClientHandler extends Thread {

    final ServerSocket s;

    // Constructor
    public ClientHandler(ServerSocket s) {
        this.s = s;
    }

    public void run() {

        Socket s = null;
        try {
            s = this.s.accept();
        } catch (IOException e) {
            e.printStackTrace();
        }
        while (true) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {

                BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
                // receive the answer from client


                String line = null;
                while ((line = in.readLine()) != null) {
                    System.out.println(line);
                }


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

    }

}
  

И, наконец, мои клиенты, которые также являются серверами. Я использую цикл for для чтения текста со всеми IP-адресами, ПОРТАМИ моих серверов:

     private void startSender() {

    for (MyServers servs : ServersTXT.fetchTXTofServers()) {
        BufferedWriter out;
        try (Socket s = new Socket(servs .getIP(), servs .getPort())) {
            out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            out.write(servs.info());
            out.newLine();
            out.flush();
        } catch (ConnectException err) {
            // Connection failed because not all servers on the txt are up
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
  

Комментарии:

1. Я не уверен, но похоже, что вы ClientHandler ошибаетесь. Учитывая вашу архитектуру, я думаю, вам нужно создавать один поток для каждого соединения (за каждый раз, когда accept() возвращается новое соединение). В противном случае ваш обработчик клиента просто принимает первое соединение, затем переходит в постоянный while(true) цикл и никогда не ищет второго клиента. Попробуйте протестировать именно это: один сервер, подключите к нему несколько клиентов. Вы можете это сделать?

2. Если каждый из ваших объектов «Клиент / сервер» представляет собой один поток, то вам будет очень легко создать ситуацию взаимоблокировки (например, красный поток ожидает ответа черного потока, но черный поток не может ответить, потому что он ожидает зеленого потока, а зеленый поток не может ответить, потому что он ожидает красного потока.) Я бы искал способ изменить архитектуру и разорвать этот цикл зависимостей.

3. @markspace Я считаю, что проблема в части startSender, ti не отправляет более чем одному участнику.

Ответ №1:

Мне потребовалось некоторое время, чтобы понять вашу архитектуру, и мне удалось выяснить, в чем была проблема. ClientHandler действительно ошибочен, потому что часть connection.accept() находится вне цикла while, и соединения теряются. Архитектура, которую вы пытаетесь достичь, имеет следующее правило. Как только я получу соединение, создайте поток для обработки этого соединения не только один раз, но и непрерывно. Приведенный выше код решит вашу проблему, если вы разместите его внутри функции run в потоке ClientHandler.

 ServerSocket providerSocket;
Socket connection;
InetAddress addr;
try {
    addr = InetAddress.getByName(this.broker.getIP());
    providerSocket = new ServerSocket(this.broker.getPort(), 50, addr);
    while (true) {
        connection = providerSocket.accept();
        ObjectOutputStream out = new ObjectOutputStream(connection.getOutputStream());
        ObjectInputStream in = new ObjectInputStream(connection.getInputStream());
        System.out.println(n.readUTF());
        in.close();
        out.close();
        connection.close();
    }
} catch (Exception err) {
      err.printStackTrace();
}
  

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