Disciplina Redes de Computadores
Professor Leandro Sales
Curso Engenharia de Computação
Alunos:
Joao Pedro Brito Tomé
Ruan Heleno Correa da Silva
O projeto foi feito em java contendo:
javac 11.0.10
openjdk version "11.0.10" 2021-01-19
Foi utilizado a IDE do Intellij IDEA como ambiente de desenvolvimento e até por isso a recomendamos para rodar o projeto.
Clonando repositório
git clone https://github.com/ruancorrea/Caixa_Eletronico
cd Caixa_Eletronico
Caso utilize a IDE Intellij, então abra o software no diretório do projeto. Edite as configurações para criar a execução do servidor e do(s) cliente(s)
Na classe Servidor, presente em Caixa_Eletronico/src/caixaEletronico/server, verifique se o caminho do arquivo(variável path) é "src/caixaEletronico/server/contas.txt"
public class Servidor{
private Arquivo arquivo;
private HashMap<String, Conta> contas;
private ServerSocket serverSocket;
private String path = "src/caixaEletronico/server/contas.txt";
}
Caso esteja utilizando o VS Code, é necessário instalar as extensões do Java, da Microsoft e a extensão Code Runner, e depois rodar em "Run Java"
Na classe Servidor, presente em Caixa_Eletronico/src/caixaEletronico/server, verifique se o caminho do arquivo(variável path) é "Caixa_Eletronico/src/caixaEletronico/server/contas.txt"
Neste documento há a especificação de um protocolo da camada de aplicação com arquitetura Cliente-Servidor para simular funcionalidades de um caixa eletrônico numa implementação multi-thread em que podem ser abertas várias guias de terminal representando os clientes, desde que o servidor seja executado primeiro. Oferecendo a transferência de dados de forma confiável (diferentemente da UDP), o protocolo TCP foi o escolhido para a da aplicação rodar. A porta utilizada pelo protocolo é a 5000.
Porta padrão: 5000
Arquitetura de aplicação: Cliente-Servidor
Protocolo na camada de transporte: TCP
A arquitetura de aplicação utilizada é a Cliente-Servidor. Desse modo, para o cliente possa utilizar as funcionalidades disponíveis é necessário que o servidor já esteja rodando e aguardando conexão entre Sockets e a partir disso a conexão entre os dois possa ser estabelecida e a interação das funcionalidades seja possibilitada.
A função básica do cliente é interagir com as funcionalidades presentes no terminal. Navegar entre menus, inserir senhas, entre outras formas. Ao iniciar o lado do cliente aparecerá um menu contendo as funcionalidades principais da aplicação. Dependendo da escolha das funcionalidades, o cliente é levado para outro menu de login (podendo ser requirido o nome da conta(depósito) ou o nome e a senha(saque) da conta na mesma linha separados por uma vírgula). O menu de login não aparecerá caso a opção seja para criar uma conta.
Funcionalidades | Finalidade |
---|---|
Sacar | para saque de dinheiro de uma determinada conta |
Depositar | para deposito de dinheiro de uma determinada conta |
Abrir conta | para abertura de uma nova conta |
Sair | finalizar a execução do cliente |
As funções básicas do servidor são as de aceitar conexões de múltiplos clientes, aceitar os comandos e armazenar e manipular os dados enviados pelos clientes. As funções são possibilitadas após a leitura de um arquivo chamado "contas.txt" que está na pasta do servidor, no qual está presente todas as informações das contas abertas. São três informações para cada conta, nome, senha e saldo, e no arquivo cada informação é separada por uma vírgula, e a cada quebra de linha equivale a uma conta aberta. Além das classes ServerSocket e Socket que cuidam, respectivamente, do Servidor e do Cliente.
Tem o papel de definir os padrões a serem utilizados para o envio, o recebimento e o tratamento de dados enviados.
Utilizamos o protocolo de transporte TCP.
Criamos a classe Mensagem que organiza o formato das mensagens trocadas entre o lado do cliente e o lado do Servidor. Tem variaveis como o status da operação, qual operação está querendo ser feita e uma hash que armazena os possiveis parâmetros.
Os status são:
Status | Significado |
---|---|
200 | OK |
373 | SOLICITAÇÃO |
400 | ERROR |
411 | PARAMERROR |
As operações para requisições são:
Operação | Função |
---|---|
LOGINSENHA | antes de sacar terá um login onde é requerido o nome e a senha da conta. |
LOGINNOME | antes de depositar terá um login onde é requerido o nome da conta |
SAQUE | para saque de dinheiro de determinada conta. |
DEPOSITO | para depósito de dinheiro de determinada conta. |
CRIARCONTA | para abrir conta. |
Os sockets presentes na aplicação são baseados em TCP, onde utilizamos as classes ObjectInputStream e ObjectOutputStream para tal troca de dados entre o cliente e servidor.
public void criandoSocket() throws IOException {
socket = new Socket("127.0.0.1", 5000);
System.out.println("Conectado com o servidor.");
output = new ObjectOutputStream(socket.getOutputStream());
input = new ObjectInputStream(socket.getInputStream());
}
public void finalizandoSocket() throws IOException {
input.close();
output.close();
socket.close();
System.out.println("Conexao com o servidor finalizada.");
}
private void criandoServerSocket(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
O servidor continua rodando em um loop infinito até que o desenvolvedor finalize a execução.
public void iniciarServico() throws ClassNotFoundException {
try {
//[...]
criandoServerSocket(5000);
while (true){
System.out.println("Aguardando conexao...");
Socket cliente=serverSocket.accept();
//[...]
}
} catch (IOException exception) {
System.err.println(exception.getMessage());
}
}
Cada requisição do cliente com o servidor é criada uma thread para tratar tal conexão e logo depois da troca de dados a conexão entre os dois é encerrada.
public class ClientThread implements Runnable{
// [...]
}
@Override
public void run() {
// [...]
}
Na função iniciarServico() presente na classe Servidor, temos a criação e a chamada da Thread.
public void iniciarServico() throws ClassNotFoundException {
try {
//[...]
while (true) {
System.out.println("Aguardando conexao...");
Socket cliente = serverSocket.accept();
System.out.println("Cliente " + cliente.getInetAddress() + " conectado.");
new Thread(new ClientThread(cliente, arquivo, contas)).start();
}
} catch (IOException exception) {
System.err.println(exception.getMessage());
}
}
Gerindo o comportamento do programa tanto no lado do servidor, quanto do cliente, temos a presença de dois padrões de projeto:
Lado | Padrão |
---|---|
Servidor | Command |
Cliente | Strategy |
Enquanto no lado do cliente o padrão Strategy gere a navegação pelas funcionalidades, no lado do servidor o padrão Command cuida da execução dos protocolos que devem ser chamados pela determinada funcionalidade escolhida pelo cliente.