Você está na página 1de 13

UNIVERSIDADE DO MINHO

LICENCIATURA EM ENGENHARIA E GESTÃO DE SISTEMAS DE INFORMAÇÃO

PROJETO 2022/2023:
FUNDAMENTOS DE SISTEMAS DISTRIBUÍDOS
PL1 – Grupo 4

1ª ENTREGA
Relatório de Código

A97468 A95144 A95822

Guilherme José de Sousa Inês Capa de Barros Maria Beatriz Garcez Morais
Barbosa
PresencesServer
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;

public class PresencesServer {


private static Presences presences = new Presences(120);
private static ArrayList<AtendePedidoTCP> listaUtilizadores = new ArrayList<>();
private static ArrayList<String> dezMensagensMaisRecentes = new ArrayList<>();

static int DEFAULT_PORT = 2000;

public ArrayList<AtendePedidoTCP> getListaUtilizadores() {


return listaUtilizadores;
}

public void setListaUtilizadores(ArrayList<AtendePedidoTCP> listaUtilizadores) {


this.listaUtilizadores = listaUtilizadores;
}

public ArrayList<String> getDezMensagensMaisRecentes() {


return dezMensagensMaisRecentes;
}

public void setDezMensagensMaisRecentes(ArrayList<String> dezMensagensMaisRecentes)


{
this.dezMensagensMaisRecentes = dezMensagensMaisRecentes;
}

public PresencesServer(Presences presences) {


this.presences = presences;
}

public Presences getPresences() {


return presences;
}

public void setPresences(Presences presences) {


this.presences = presences;
}

public static void iniciar() throws IOException {


Scanner scanner = new Scanner(System.in);

System.out.println("Qual é a porta que deseja operar?");


DEFAULT_PORT = scanner.nextInt();

System.out.println("Qual é o valor do parametro SESSION_TIMEOUT que deseja?");


int timeOut = scanner.nextInt();

ServerSocket servidor = null;

Presences presences = new Presences(timeOut);

PresencesServer presencesServer = new PresencesServer(presences);


servidor = new ServerSocket(DEFAULT_PORT);
System.out.println("Servidor a' espera de ligacoes no porto " + DEFAULT_PORT);
iniciarLoop();
while (true) {
try {
Socket ligacao = servidor.accept();
AtendePedidoTCP atendePedidoTCP = new AtendePedidoTCP(ligacao,
presencesServer);
atendePedidoTCP.start();
listaUtilizadores.add(atendePedidoTCP);//adiciona um novo utilizador à
lista de atendepedidotcp (para ser possivel enviar mensagem para todos os utilizadores)

} catch (IOException e) {
System.out.println("Erro na execucao do servidor: " + e);
System.exit(1);
}

}
}
private static void iniciarLoop() {
Timer timer =new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
sessionTimeOut();
} catch (IOException e) {
e.printStackTrace();
}

}
}, 1*1000, 1* 1000); //repete a cada 120 segundos
}

public static void sessionTimeOut() throws IOException {


Vector<String> utilizadoresAtivos = presences.getNicknameList();

ArrayList<AtendePedidoTCP> utilizadoresInativos = new ArrayList<>();

for (AtendePedidoTCP atendePedidoTCP : listaUtilizadores) {


if (!utilizadoresAtivos.contains(atendePedidoTCP.getNickname())) {
utilizadoresInativos.add(atendePedidoTCP);
}
}

for (AtendePedidoTCP a : utilizadoresInativos) {


a.getOut().println("SESSION_TIME_OUT");
a.getIn().close();
a.getOut().close();
a.getLigacao().close();
listaUtilizadores.remove(a);
}

public static void main(String[] args) {


try {
iniciar();
} catch (IOException e) {
e.printStackTrace();
}
AtendePedidoTCP
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class AtendePedidoTCP extends Thread {

private BufferedReader in;


private PrintWriter out;
private String nickname;
private Socket ligacao;
private PresencesServer presencesServer;

public BufferedReader getIn() {


return in;
}

public void setIn(BufferedReader in) {


this.in = in;
}

public PrintWriter getOut() {


return out;
}

public void setOut(PrintWriter out) {


this.out = out;
}

public void setNickname(String nickname) {


this.nickname = nickname;
}

public Socket getLigacao() {


return ligacao;
}

public void setLigacao(Socket ligacao) {


this.ligacao = ligacao;
}

public AtendePedidoTCP(Socket Ligacao, PresencesServer presencesServer) throws


IOException { //inicializar as componentes do atendepedidotcp
this.in = new BufferedReader(new InputStreamReader(Ligacao.getInputStream()));
this.out = new PrintWriter(Ligacao.getOutputStream(), true);
this.ligacao = Ligacao;
this.presencesServer = presencesServer;
}

public String getNickname() {


return nickname;
}

//receber as mensagens dos utilizadores


public void run() {
String pedido;

try {
while (ligacao.isConnected()) {
pedido = in.readLine(); //lê o pedido
if(pedido != null) {
verificarTipomensagem(pedido); //filtra o pedido por tipo
}
}
} catch (IOException e) {
//throw new RuntimeException(e);
}
}

private void verificarTipomensagem(String mensagemPortratar) throws IOException {


String tipoMensagem, mensagem;
String[] sp = mensagemPortratar.split(":"); // dividir as string num array de
strings
tipoMensagem = sp[0]; //separar o cabeçalho do nickname

int indexOfSpace = mensagemPortratar.indexOf(':'); // buscar o index do


primeiro :
mensagem = mensagemPortratar.substring(indexOfSpace + 1); // buscar a string
depois do primeiro :

responderTipoPedido(tipoMensagem, mensagem); //responder ao pedido do


utilizador conforme o tipo de pedido feito
}

public void responderTipoPedido(String tipoPedido, String mensagem) throws


IOException { //temos dois tipos de mensagem
switch (tipoPedido) {
case "SESSION_UPDATE_REQUEST":
sessionUpdateRequest(mensagem);
break;
case "AGENT_POST":
agentPost(nickname + ":" + mensagem); // agent post é para enviar a
mensagem para o feed na estrutura "nickname:post"
break;
}
}

//adiciona a mensagem à lista das 10 mensagens mais recentes


private void agentPost(String mensagem) throws IOException {
adicionarMensagensMaisRecentes(mensagem);

presencesServer.getPresences().getPresences(String.valueOf(ligacao.getRemoteSocketAddres
s()), nickname);//cada vez que ele faz um AgentPost atualizamos o tempo.
enviarSessionUpdateParaTodosUtilizadores();
}

private void sessionUpdateRequest(String mensagem) throws IOException {


if (nickname == null) {
nickname = mensagem; //se ele nao tiver nickname, entao o nickname é igual
ao que ele mandou para o servidor
}

presencesServer.getPresences().getPresences(String.valueOf(ligacao.getRemoteSocketAddres
s()), nickname); //cada vez que ele faz um sessionUpdateRequest atualizamos o tempo.
enviarSessionUpdateParaTodosUtilizadores(); //passo 9
}

private void adicionarMensagensMaisRecentes(String mensagem) {


presencesServer.getDezMensagensMaisRecentes().add(mensagem);
}

private void enviarSessionUpdateParaTodosUtilizadores() {


for (AtendePedidoTCP atendePedidoTCP : presencesServer.getListaUtilizadores()) {
//vamos buscar todos os utilizadores online
atendePedidoTCP.out.println("SESSION_UPDATE");
atendePedidoTCP.sessionUpdate(); //para cada utilizador, enviamos um
SESSION_UPDATE
}
}

private void sessionUpdate() {


int tamanhoUtilizadores =
(presencesServer.getPresences().getNicknameList().size()); //size = numero de
utilizadores que existem
out.println(Integer.toString(tamanhoUtilizadores)); //mandar o numero de
utilizadores para o utilizador a receber

for (int i = 0; i < presencesServer.getPresences().getNicknameList().size();


i++) {
out.println(presencesServer.getPresences().getNicknameList().get(i));
//enviar o nickname de cada cliente
}

int tamanhoMensagens = presencesServer.getDezMensagensMaisRecentes().size();


if (tamanhoMensagens <= 10) {
out.println(Integer.toString(tamanhoMensagens));
for (int i = 0; i < tamanhoMensagens; i++) {
out.println(presencesServer.getDezMensagensMaisRecentes().get(i));
}

} else {
out.println(Integer.toString(10));
int inicio = presencesServer.getDezMensagensMaisRecentes().size() - 10;
//vemos a primeira mensagem a enviar
int fim = presencesServer.getDezMensagensMaisRecentes().size(); //
vemos o fim

for (int i = inicio; i < fim; i++) { //for para percorrer as


mais recentes
out.println(presencesServer.getDezMensagensMaisRecentes().get(i));
}
}
}

}
IPInfo
class IPInfo {
private String nickname; //guardar o nickname também
private String ip;
private long lastSeen;

public IPInfo(String ip, long lastSeen, String nickname) {


this.ip = ip;
this.lastSeen = lastSeen;
this.nickname = nickname;
}

public String getIP() {


return this.ip;
}

public void setLastSeen(long time) {


this.lastSeen = time;
}

public String getNickname() {


return nickname;
}

public void setNickname(String nickname) {


this.nickname = nickname;
}

public boolean timeOutPassed(int timeout) {


boolean result = false;
long timePassedSinceLastSeen = new Date().getTime() - this.lastSeen;
if (timePassedSinceLastSeen >= timeout) result = true;
return result;
}
}
Presences
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;

public class Presences {


int time_Out;

public Presences(int time_Out) {


this.time_Out = time_Out;
}

private static Hashtable<String, IPInfo> presentIPs = new Hashtable<String,


IPInfo>();
private static int cont = 0;

public Vector<String> getPresences(String IPAddress, String nickname) {


long actualTime = new Date().getTime();
cont = cont + 1;

//Assume-se que o IP e valido!!!!!


synchronized (this) {
if (presentIPs.containsKey(IPAddress)) {
IPInfo newIp = presentIPs.get(IPAddress);
newIp.setLastSeen(actualTime);
} else {
IPInfo newIP = new IPInfo(IPAddress, actualTime, nickname);
presentIPs.put(IPAddress, newIP);
}
}
return getNicknameList();
}

public Vector<String> getNicknameList() {


Vector<String> result = new Vector<String>();

for(IPInfo element : presentIPs.values()){


if (!element.timeOutPassed(time_Out * 1000)) {
result.add(element.getNickname()); //enquanto os 2 minutos nao
passarem, o utilizador continua a aparecer online
}

}
return result;
}
}
ConfiguracoesCliente
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

public class ConfiguracoesCliente extends JFrame{


private JButton button1;
private JPanel panel1;
private JTextField tfPorta;
private JTextField tfEndereco;

public ConfiguracoesCliente() {
setTitle("Configurações do Cliente");
setSize(700, 300);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setContentPane(panel1);

button1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {

String enderecoIP = tfEndereco.getText();


String porta = tfPorta.getText();
InterfaceCliente interfaceCliente = new InterfaceCliente(enderecoIP,
porta);
dispose();

} catch (IOException ex) {


ex.printStackTrace();
}

}
});
}

public static void main(String[] args) {


ConfiguracoesCliente configuracoesCliente = new ConfiguracoesCliente();
configuracoesCliente.setVisible(true);

}
}
InterfaceCliente
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;

public class InterfaceCliente extends JFrame {


private JLabel nicknameBtn;
private JTextField usernameTf;
private JButton connectBtn;
private JButton disconnectBtn;
private JButton sendBtn;
private JTable table1;
private JTable table2;
private JScrollPane tabelaPresencas;
private JButton verPresençasButton;
private javax.swing.JPanel JPanel;
private JTextField tfSendMessage;
private JScrollPane tabelaMensagens;
private JTextArea taSendMessage;

static DefaultTableModel model = new DefaultTableModel();


static DefaultTableModel model2 = new DefaultTableModel();

static int DEFAULT_PORT = 2000;


static String DEFAULT_HOST = "127.0.0.1";
private BufferedReader in;
private PrintWriter out;
private Socket ligacao;
private Scanner scanner;
private String nickname;
private Timer timer = new Timer();

private static InterfaceCliente interfaceCliente;

public InterfaceCliente(String enderecoIP, String porta) throws IOException {


//inicializar a nossa interface do cliente
table1.setModel(model);
model.addColumn("Mensagens"); //cabeçalho da tabela de mensagens

//panel representa toda a nossa interface


setContentPane(JPanel);
setTitle("Forum");
setSize(700, 700);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);

table2.setModel(model2);
model2.addColumn("Utilizadores Online:"); //cabeçalho da tabela de utilizadores
online

if(!enderecoIP.isEmpty() && !porta.isEmpty()){


DEFAULT_HOST = enderecoIP;
DEFAULT_PORT = Integer.parseInt(porta);
}

connectBtn.addActionListener(new ActionListener() { //botao para se conectar ao


chat
@Override
public void actionPerformed(ActionEvent e) {
try {
iniciar();
} catch (IOException ex) {
throw new RuntimeException(ex);
}

if (usernameTf.getText().isBlank()) { //erro se se tentar conectar com o


campo do nickname vazio
JOptionPane.showMessageDialog(null, "Escolha um nickname!", "ERRO!",
JOptionPane.ERROR_MESSAGE);

} else {
nickname = usernameTf.getText();
inicarLoop(nickname, timer);
receberMensagem();
}
}
});

sendBtn.addActionListener(new ActionListener() { //botao para enviar mensagens


para o chat
@Override
public void actionPerformed(ActionEvent e) {
String mensagem = tfSendMessage.getText();
enviarMensagem(mensagem); //enviar mensagem para o servidor
tfSendMessage.setText(""); //mete o text field vazio depois de enviarmos
a mensagem
}
});

private void inicarLoop(String nickname, Timer timer) {


timer.schedule(new TimerTask() {
@Override
public void run() {
try {
//removemos para que nao tenhamos repetições quando executamos o
metodo
model.getDataVector().removeAllElements(); //remove todos os
elementos da tabela das mensagens
model2.getDataVector().removeAllElements(); //remove todos os
elementos da tabela dos utilizadores online
sessionUpdateRequest(nickname); //executa o metodo
} catch (IOException e) {
e.printStackTrace();
}
}
}, 0, 120 * 1000); //repete a cada 120 segundos
}

public void iniciar() throws IOException { //botao para iniciar as componentes todas
InetAddress serverAdress = InetAddress.getByName(DEFAULT_HOST);
ligacao = new Socket(serverAdress, DEFAULT_PORT);
in = new BufferedReader(new InputStreamReader(ligacao.getInputStream()));
out = new PrintWriter(ligacao.getOutputStream(), true);

public void sessionUpdateRequest(String nickname) throws IOException {


out.println("SESSION_UPDATE_REQUEST:" + nickname); //envia para o servidor o
nickname do utilizador quando ele se conecta

public void enviarMensagem(String mensagemEnviar) {


out.println("AGENT_POST:" + mensagemEnviar); //envia para o servidor a mensagem
que o utilizador pretende enviar

public void receberMensagem() { //se a mensagem recebida for session_update, remove


todos os elementos da tabela das mensagens e da tabela dos utilizadores online
new Thread(new Runnable() {
@Override
public void run() {
String mensagemRecebida;

while (ligacao.isConnected()) {
try {
mensagemRecebida = in.readLine();
if (mensagemRecebida.equals("SESSION_UPDATE")) {
model.getDataVector().removeAllElements();
model2.getDataVector().removeAllElements();
receberSessionUpdate();

} else if (mensagemRecebida.equals("SESSION_TIME_OUT")) {
in.close();
out.close();
ligacao.close();
timer.cancel();
model.getDataVector().removeAllElements();
model2.getDataVector().removeAllElements();
model.fireTableDataChanged();
model2.fireTableDataChanged();

int dialogButton = JOptionPane.showConfirmDialog(null,


"Gostaria de se reconectar? ", "voce foi desconectado", JOptionPane.YES_NO_OPTION);
if (dialogButton == JOptionPane.YES_OPTION) {
iniciar();
Timer timer2 = new Timer();
inicarLoop(nickname, timer2);
receberMensagem();

} else {
dispose();
}

break;
} else {

}
} catch (IOException e) {
System.out.println("Erro ao comunicar com o servidor ");
}
}

}
}).start();

private void receberSessionUpdate() {


ArrayList<String> presencas = new ArrayList<>(); //guarda num array de presenças
os nicknames dos utilizadores
ArrayList<String> mensagens = new ArrayList<>(); //guarda num array de
mensagens dos utilizadores

int tamanhoPresencas = 0;
try {
tamanhoPresencas = Integer.parseInt(in.readLine());

} catch (IOException e) {
throw new RuntimeException(e);
}
//percorre o array de presenças e imprime o nickname dos utilizadores online / o
metodo conectar(...) retorna um array c os nicknames todos
for (int i = 0; i < tamanhoPresencas; i++) {
try {
model2.addRow(new String[]{in.readLine()}); //listar na tabela cada
nickname
} catch (IOException e) {
throw new RuntimeException(e);
}
}
int tamanhoMensagens = 0;
try {
tamanhoMensagens = Integer.parseInt(in.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
for (int i = 0; i < tamanhoMensagens; i++) {
try {
model.addRow(new String[]{in.readLine()}); //listar na tabela cada
mensagem
} catch (IOException e) {
throw new RuntimeException(e);
}
}
connectBtn.setEnabled(false);
}

Você também pode gostar