/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package algoritmoricartagrawala; import java.io.IOException; import static java.lang.Math.random; import static java.lang.StrictMath.random; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.Scanner; /** * * @author giovanne.gaspareto */ public class AlgoritmoRicartAgrawala { static InetAddress grupo; static MulticastSocket s; static DatagramPacket msg; static DatagramPacket recv; private static Scanner keyboard; static boolean executarProcesso = true; static boolean aguardaPermissaoRegiaoCritica = false; static boolean regiaoCritica = false; static final String GROUP_IP = "224.0.0.1"; static final int MULTICAST_PORT = 2000; static int IDProcesso = 0; static String mensagem = ""; static int numeroProcessosGrupo = 0; static int tempoRandom = 0; static int idProcessoNaRegiaoCritica = 0; static int idRecebido = 0; static int proximo = 0; static final String OK_STRING = "ok"; static final String DESCONECTAR_STRING = "q"; static final String DIVISOR_STRING = ";"; static final String GRUPO_COMPLETO_STRING = "gc"; static final String EXISTE_PROCESSO_REGIAO_CRITICA = "regiao critica"; static final String REQUISICAO_REG_CRITICA_STRING = "rc"; static final String SAINDO_REGIAO_CRITICA_STRING = "sc"; static final String ENTROU_REGIAO_CRITICA_STRING = "ec"; static final int NOVO_MEMBRO = 1; static final int GRUPO_COMPLETO = 2; static final int REQUISICAO_REG_CRITICA = 3; static final int SAINDO_REGIAO_CRITICA = 4; static final int ENTROU_REGIAO_CRITICA = 5; static List listaEsperaRegiaoCritica = new ArrayList(); //lista com IDs dos processos aguardando pela regiao critica public static String receiveMessageGroup(){ byte[] buf=new byte[1000]; recv=new DatagramPacket(buf, buf.length); try { s.setSoTimeout(10); s.setLoopbackMode(false); // System.out.println("timeout no recevei sem nada: " + s.getSoTimeout()); s.receive(recv); byte[] dest=new byte[recv.getLength()]; System.arraycopy(recv.getData(), 0, dest, 0, dest.length); String mensagemRecebida = new String(recv.getData(),recv.getOffset(),recv.getLength()); // System.err.println("Mensagen recebida: "+ mensagemRecebida); return mensagemRecebida; } catch (SocketTimeoutException ex) { // Logger.getLogger(ProcessoSender.class.getName()).log(Level.SEVERE, null, ex); return "x;0;0"; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return "x;0;0"; } } public static void sendMessageGroup(String msgStr) { msg=new DatagramPacket(msgStr.getBytes(), msgStr.length(),grupo, 2000); // System.out.println("Enviando mensagem para o grupo ..."); try { s.send(msg); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //Funcao de configuracao public static void setUp() { try { System.setProperty("java.net.preferIPv4Stack", "true"); // somente pra mac no wifi grupo=InetAddress.getByName(GROUP_IP); s=new MulticastSocket(MULTICAST_PORT); System.err.println("Entrando no grupo ..."); s.joinGroup(grupo); System.err.println("Ok."); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static int geraRandomEntre(int min, int max){ Random rn = new Random(); return rn.nextInt(max-min+1)+min; } /** * @param args the command line arguments */ public static int trataMensagem(String mensagemRecebida, DatagramPacket PacketLider){ String[] partes = mensagemRecebida.split(DIVISOR_STRING); String operacao = partes[0]; String mensagem = partes[1]; idRecebido = Integer.parseInt(mensagem); if(operacao.equals(OK_STRING)){ return NOVO_MEMBRO; } else if(operacao.equals(GRUPO_COMPLETO_STRING)){ return GRUPO_COMPLETO; }else if(operacao.equals(REQUISICAO_REG_CRITICA_STRING)){ return REQUISICAO_REG_CRITICA; }else if(operacao.equals(SAINDO_REGIAO_CRITICA_STRING)){ idProcessoNaRegiaoCritica = 0; return SAINDO_REGIAO_CRITICA; }else if(operacao.equals(ENTROU_REGIAO_CRITICA_STRING)){ idProcessoNaRegiaoCritica = Integer.parseInt(mensagem); return ENTROU_REGIAO_CRITICA; } return -1; } public static void defineIDProcesso(){ keyboard = new Scanner(System.in); System.out.println("Informe o ID deste processo: "); IDProcesso = keyboard.nextInt(); } public static void lerGrupoTrataMensagem(){ switch(trataMensagem(receiveMessageGroup(),recv)){//só cria timer apos estar de fato atuando na regiao critica, so acontecera quando receber um ok que o processo anterior liberou ela //ler mensagens ate receber ok que a regiao critica esta livre case REQUISICAO_REG_CRITICA: //Recebeu uma requisicao de regiao critica, todos atualizam a lista de espera listaEsperaRegiaoCritica.add(idRecebido); proximo = listaEsperaRegiaoCritica.get(0); if(proximo == IDProcesso && idProcessoNaRegiaoCritica == 0){ //é o primeiro da fila e nao ha nenhum processo na regiao critica aguardaPermissaoRegiaoCritica = false; regiaoCritica = true; } break; case SAINDO_REGIAO_CRITICA: //verificar se seu proprio ID é o proximo a entrar na regiao critica, se for, envia que entrou e inicia timer, senao salva o id de quem entrou proximo = listaEsperaRegiaoCritica.get(0); System.out.println("[Processo "+ IDProcesso + "] Proximo da lista: " + proximo); if(proximo == IDProcesso){ aguardaPermissaoRegiaoCritica = false; //este processo é o proximo da fila, sai do loop de espera espera //sendMessageGroup(ENTROU_REGIAO_CRITICA_STRING + DIVISOR_STRING + IDProcesso); //avisa outros processos que esta entrando regiaoCritica = true; } break; case ENTROU_REGIAO_CRITICA: //se idProcesso = idProcessoNaRegiaoCritica, significa que pode entrar. aguardaPermissaoRegiaoCritica = false, regiaoCritica = true // remove ID do processo que entrou da lista de espera listaEsperaRegiaoCritica.remove(0); break; } } public static void lerGrupoRegiaoNaoCritica(){ switch(trataMensagem(receiveMessageGroup(),recv)){//só cria timer apos estar de fato atuando na regiao critica, so acontecera quando receber um ok que o processo anterior liberou ela //ler mensagens ate receber ok que a regiao critica esta livre case REQUISICAO_REG_CRITICA: //Recebeu uma requisicao de regiao critica, todos atualizam a lista de espera listaEsperaRegiaoCritica.add(idRecebido); break; case ENTROU_REGIAO_CRITICA: //se idProcesso = idProcessoNaRegiaoCritica, significa que pode entrar. aguardaPermissaoRegiaoCritica = false, regiaoCritica = true // remove ID do processo que entrou da lista de espera // if(IDProcesso != idRecebido){ //somente se for outro processo lendo que alguem entrou. Se for o proprio processo, ele ja se removeu da lista ao avaliar que era o proximo listaEsperaRegiaoCritica.remove(0); break; } } public static void aguardaMembrosDoGrupo(){ while(numeroProcessosGrupo<3){ switch(trataMensagem(receiveMessageGroup(),recv)){ case NOVO_MEMBRO: numeroProcessosGrupo ++; System.out.println("Novo processo Conectado ao Grupo!"); break; case GRUPO_COMPLETO: numeroProcessosGrupo = 3; break; default: // System.out.println("Case Default da espera grupo"); break; } } sendMessageGroup(GRUPO_COMPLETO_STRING+DIVISOR_STRING+IDProcesso); } public static void main(String[] args) { setUp(); defineIDProcesso(); sendMessageGroup(OK_STRING+DIVISOR_STRING+IDProcesso); aguardaMembrosDoGrupo(); System.out.println("Grupo completo! Iniciar execucao."); tempoRandom = geraRandomEntre(2,16); //tempoRandom = 3; TimerProcessos timerAleatorio = new TimerProcessos(tempoRandom); System.out.println("[Processo " + IDProcesso + "] Entrando na regiao nao critica por " + tempoRandom + "s"); while(executarProcesso){ if(timerAleatorio.shouldCreate){ //passou o tempo, entra ou sai da regiao critica if(aguardaPermissaoRegiaoCritica){//se estava na critica, agora nao esta mais aguardaPermissaoRegiaoCritica = false; tempoRandom = geraRandomEntre(2,16); }else{//se estava fora, agora fica na critica aguardaPermissaoRegiaoCritica = true; } } if(aguardaPermissaoRegiaoCritica){ //fazer coisas da regiao critica System.out.println("[Processo " + IDProcesso + "] Aguardando entrada na regiao critica!"); //Notifica a todos que deseja estar na regiao critica sendMessageGroup(REQUISICAO_REG_CRITICA_STRING + DIVISOR_STRING + IDProcesso); while(aguardaPermissaoRegiaoCritica){ lerGrupoTrataMensagem(); } sendMessageGroup(ENTROU_REGIAO_CRITICA_STRING + DIVISOR_STRING + IDProcesso); //avisa outros processos que esta entrando na regiao critica //Iniciar timer da regiao critica timerAleatorio.cancelTimer(); timerAleatorio = new TimerProcessos(tempoRandom); System.err.println("[Processo " + IDProcesso + "] Entrando na regiao critica! Tempo dentro da regiao: " + tempoRandom + "s"); regiaoCritica = true; while(regiaoCritica){ //verifica timer, muda regiaoCritica para false apos fim do timer if(timerAleatorio.shouldCreate){ regiaoCritica = false; //Inicia timer da regiao nao critica timerAleatorio.cancelTimer(); tempoRandom = geraRandomEntre(2,16); timerAleatorio = new TimerProcessos(tempoRandom); } lerGrupoTrataMensagem(); //Ainda ler grupo, para atualizar lista de espera } System.err.println("[Processo " + IDProcesso + "]Fim da regiao critica!"); sendMessageGroup(SAINDO_REGIAO_CRITICA_STRING + DIVISOR_STRING + IDProcesso); //notifica que saiu da regiao critica System.out.println("[Processo " + IDProcesso + "] Executando na regiao nao critica por " + tempoRandom + "s"); }else{ //fazer coisas da regiao nao critica //Ler grupo para atualizar controle de quem esta na regiao critica e atualizar a lista de espera lerGrupoRegiaoNaoCritica(); } } System.exit(0); } }