Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

JAVA RMI - Cliente A e B enviar info, servidor dar resposta

Primeiramente, olá e bom dia.

Estou tentando desenvolver uma aplicação com RMI para fins acadêmicos, mas estou com dificuldade em como fazer uma parte da minha ideia.

O que eu queria era fazer um programa, como uma calculadora (por exemplo), onde um Cliente A entraria com um valor (X = 5, por ex) e Cliente B com outro (Y = 10, por ex). Nisso, o servidor replicaria uma mensagem para ambos com o resultado (X + Y = 15).

A minha dúvida é só realmente essa, como eu posso fazer com que Cliente A entre com X, Cliente B com Y e devolver ambos para o servidor para que ele use isso para resolver o problema. Tendo essa ideia, eu consigo ir além e realmente fazer o que eu quero.

Se alguém puder dar um help, agradeço!

R.

4 respostas

Oi Ramom, o server do rmi sobe apenas uma instancia do objeto que vai receber as chamadas de todos clientes. O problema é que o rmi não permite que o server chame o cliente diretamente.. .vc sempre precisa ter uma chamada do cliente... Por isso eu acho que esse seu esquema não vai funcionar.. vc precisava de alguém que fizesse o papel de broker de mensageria.. para plugar listeners.

Caso tenha uma forma, só com rmi, eu realmente não conheço.

Perdão, mas me perdi um pouco no final. Como assim um broker? Alguém que controlasse o fluxo das mensagens?

Ontem estava dando uma olhada em Threads e pensei numa possibilidade, mas não sei como implementar e não sei se é possível também:

Do lado do servidor, um método que tivesse dois parâmetros que viriam de mais outros dois métodos diferentes. Enquanto ele não tivesse um resultado de ambos, ele ficaria num loop infinito esperando.

Pelo lado do cliente, eu pensei em "chapar" mesmo um "if" e "else" onde um teria o método 1 e o outro o método 2. Nisso, eu iria iniciar dois clientes e iniciaria eles com as opções respectivas.

Algo assim seria possível? Ainda não entendi muito bem como funciona as Threads, mas num exemplo que vi ontem, me fez crer que algo assim seria possível (lógico, da maneira que descrevo será completamente absurdo, mas...)

edit: Eu também vi que houve gente que fez projeto de xadrez e jogo da velha em RMI. Não seria algo do tipo? Enquanto A joga, B espera. Na hora da jogada, a info vai para o servidor e então é a vez de B.

Pelo menos nessa ideia, tem o conceito de turno. Isso me seria útil também.

O máximo que pode acontecer é alguém ficar fazendo chamada remota verificando se algum estado mudou? mas no rmi, não rola o server notificar o cliente. Talvez a thread tenha entrado para isso no seu exemplo. E o broker era um cara que controlaria as mensagens, exatamente.. só que talvez seja demais para o seu caso.. talvez um loop que fique verificando já valha.

solução!

Consegui uma maneira de fazer mais ou menos o que eu quero. Peguei o código com um usuário do GUJ de nome staroski. Pra quem eventualmente precisar de algo parecido, acredito ser um bom ponto de partida.

Acredito que o tópico também já pode ser fechado, segue os códigos:

Interface do serviço que recebe o X e o Y e permite que seja registrado um listener:

package exemplo.rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Servico extends Remote {

    void addListener(ServicoListener listener) throws RemoteException;

    void setX(double valor) throws RemoteException;

    void setY(double valor) throws RemoteException;
}

Interface do listener para o serviço acima:

package exemplo.rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ServicoListener extends Remote {

    void calculoEfetuado(double resultado) throws RemoteException;
}

Implementação da interface do serviço:

package exemplo.rmi.server;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;

import exemplo.rmi.Servico;
import exemplo.rmi.ServicoListener;

class ImplementacaoServico implements Servico {

    private final List<ServicoListener> listeners = new ArrayList<>();

    private boolean setouX;
    private boolean setouY;

    private double valorX;
    private double valorY;

    @Override
    public void addListener(ServicoListener listener) throws RemoteException {
        listeners.add(listener);
    }

    @Override
    public void setX(double valor) throws RemoteException {
        valorX = valor;
        setouX = true;
        verifica();
    }

    @Override
    public void setY(double valor) throws RemoteException {
        valorY = valor;
        setouY = true;
        verifica();
    }

    private void verifica() {
        if (setouX && setouY) {
            double resultado = valorX + valorY;
            for (ServicoListener listener : listeners) {
                try {
                    listener.calculoEfetuado(resultado);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            setouX = false;
            setouY = false;
        }
    }
}

Implementação do servidor que disponibiliza o serviço acima:

package exemplo.rmi.server;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import exemplo.rmi.Servico;

public class Servidor {

    public static void main(String args[]) {
        try {
            String nomeServico = "MeuServico";
            int porta = 12345;

            Servico servico = new ImplementacaoServico();
            Servico servicoDistribuido = (Servico) UnicastRemoteObject.exportObject(servico, 0);

            Registry registry = LocateRegistry.createRegistry(porta);
            registry.bind(nomeServico, servicoDistribuido);
            System.out.printf("Servico disponivel: %s%n", nomeServico);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Implementação do cliente A que faz o setX:

package exemplo.rmi.client;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import exemplo.rmi.Servico;
import exemplo.rmi.ServicoListener;

public class ClienteA implements ServicoListener {

    public static void main(String[] args) {
        try {
            String nomeServico = "MeuServico";
            int porta = 12345;

            ServicoListener clienteA = new ClienteA();
            ServicoListener clienteAdistribuido = (ServicoListener) UnicastRemoteObject.exportObject(clienteA, 0);

            Registry registry = LocateRegistry.getRegistry(porta);
            Servico servicoRemoto = (Servico) registry.lookup(nomeServico);
            servicoRemoto.addListener(clienteAdistribuido);

            double valor = 20;
            System.out.println("Cliente A enviando: " + valor);
            servicoRemoto.setX(valor);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void calculoEfetuado(double resultado) throws RemoteException {
        System.out.println("Servidor devolveu para Cliente A o resultado: " + resultado);
    }
}

Implementação do cliente B, que faz o setY perceba que o código é análogo ao do cliente A, você pode criar uma abstração para isso:

package exemplo.rmi.client;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import exemplo.rmi.Servico;
import exemplo.rmi.ServicoListener;

public class ClienteB implements ServicoListener {

    public static void main(String[] args) {
        try {
            String nomeServico = "MeuServico";
            int porta = 12345;

            ServicoListener clienteB = new ClienteB();
            ServicoListener clienteBdistribuido = (ServicoListener) UnicastRemoteObject.exportObject(clienteB, 0);

            Registry registry = LocateRegistry.getRegistry(porta);
            Servico servicoRemoto = (Servico) registry.lookup(nomeServico);
            servicoRemoto.addListener(clienteBdistribuido);

            double valor = 10;
            System.out.println("Cliente B enviando: " + valor);
            servicoRemoto.setY(valor);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void calculoEfetuado(double resultado) throws RemoteException {
        System.out.println("Servidor devolveu para Cliente B o resultado: " + resultado);
    }
}