Baixe o app para aproveitar ainda mais
Prévia do material em texto
UFJF UNIVERSIDADE FEDERAL DE JUIZ DE FORA Redes de Computadores Aluno: Gabriel Martins Quintana Vieira Marques (201835009) Professor: Alex Borges Vieira 1) Descrição do trabalho Esse trabalho foi feito com intuito de desenvolver um protocolo cliente-servidor utilizando threads. Um servidor multithread é um servidor que manipula múltiplas requisições de forma simultânea e em paralelo. No nosso caso o servidor irá permitir que vários clientes possam se conectar ao mesmo tempo a um único servidor. Neste documento em diante irei mostrar todo o processo de desenvolvimento que eu segui e também como implementei esse problema. 2) Tomada de decisões O trabalho foi desenvolvido utilizando a linguagem de programação Python devido a extensa documentação existente e suas inúmeras aplicações. É uma linguagem de fácil aprendizado e possui uma vasta comunidade em ascensão. Para a questão do código em si, foram utilizadas somente as bibliotecas de socket, threading e colorama. A biblioteca socket foi utilizada para fazer o protocolo cliente servidor com o módulo socket. Threading foi utilizada para tornar o servidor multithread e colorama foi usado para facilitar a leitura do usuário com diferentes cores de print no terminal. 3) Estruturação do trabalho Antes de começar a falar da estruturação do trabalho, gostaria de dizer que resumi um pouco a explicação aqui porque expliquei de forma mais detalhada no vídeo enviado. Dito isso para entender melhor a estruturação do trabalho é importante citar primeiramente que o código foi dividido em dois arquivos diferentes, um deles é o arquivo client.py onde está o código da parte do cliente, e o outro é o arquivo server.py onde está o código da parte do servidor. Client.py Para o código do cliente não utilizei classes. Criei variáveis de IP e PORT(Porta) e pedi como input para o usuário conectar ao respectivo servidor com esses valores. Utilizei um loop para manter o usuário conectado e podendo escrever mensagens para o servidor enquanto ele não digitasse o comando quit. Coloquei também mensagens de erro caso o usuário digite um comando errado. Server.py Para o código do servidor utilizei a classe handle_client que é a classe que será responsável por lidar com a parte do cliente (comandos, decodificação, entre outros) enquanto o mesmo estiver conectado. Utilizei também um loop para permitir que o servidor continue aceitando clientes enquanto estiver conectado, nesse loop também temos a utilização da thread que é de extrema importância e será responsável por permitir que o servidor comporte mais de um cliente ao mesmo tempo. 4) Entrada e saída Entrada As entradas são feitas ao lado do cliente (ao rodar o arquivo client.py) é pedido para que ele digite o IP e o PORT(Porta) do Host(servidor) que ele deseja se conectar. Saída No caso da minha implementação, como não foi pedido, não coloquei nenhuma saída. Tudo é feito no terminal. 5) Como utilizar o programa Instalação Para utilizar o programa é bem fácil. ● É necessário instalar o python na máquina que irá realizar os testes. Para isso é preciso que o usuário tenha acesso a internet e possa acessar o site https://www.python.org/downloads para baixá-lo. O usuário deverá https://www.python.org/downloads/ verificar qual o Sistema Operacional de sua máquina, a versão do python desejada (no caso em questão foi utilizado o python3) e seguir a orientação descrita no site para continuar com a instalação. ● Foi utilizado a biblioteca colorama, caso o usuário tenha algum problema é importante verificar o site https://pypi.org/project/colorama/ e seguir os passos, realizando a instalação das dependências. ● Após baixar o python e verificar as bibliotecas utilizadas, o usuário deve baixar os arquivos client.py e server.py. Após todos esses passos, e com o client.py e server.py em seu computador, o usuário poderá começar a utilizar o programa. Utilização Para a utilização temos os seguintes passos. 1)Abrir o terminal clicando com o botão direito na pasta que está o arquivo server.py, e digitar no terminal que foi aberto o comando “python3 server.py” https://pypi.org/project/colorama/ 2)Após o passo 1 o servidor foi iniciado, agora o usuário deve deixar esse terminal aberto, e abrir outro na mesma pasta e rodar o comando “client.py”. 3) Pronto o usuário foi conectado e já pode enviar mensagens para o servidor. Os comandos para o usuário estão descritos no terminal. Caso ele queira mandar uma mensagem para o servidor ele deve digitar o comando echo <mensagem>. Já se ele quiser finalizar a conexão com servidor ele deve digitar o comando echo <quit>. Se o usuário não colocar o comando echo antes das mensagens o servidor nem irá recebê-las. 6) Código fonte Cliente import socket from colorama import Fore, Back, Style IP = input("Digite o IP do servidor -> ") PORT = input("Digite a porta do servidor -> ") PORT = int(PORT) client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((IP,PORT)) print('\033[32m' + f"Você se conectou no servidor" + '\033[39m') print('\033[35m' + f"{Style.BRIGHT}Como usar o servidor:" + '\033[39m') print('\033[35m' + f"{Style.BRIGHT}-> echo 'mensagem' [para digitar uma mensagem]" + '\033[39m') print('\033[35m' + f"{Style.BRIGHT}-> quit [para finalizar sua conexão]" + '\033[39m') connected = True while connected: message = input(">>> ") if (message.startswith("echo") or message == "quit"): client.send(message.encode("utf-8")) if (message == 'quit'): print('\033[31m' + 'Você foi desconectado!' + '\033[39m') connected = False else: message = client.recv(1024).decode("utf-8") print('\033[36m' + f"{Style.BRIGHT}[Resposta do servidor] {message}" + '\033[39m') else: print('\033[33m' + f"{Style.BRIGHT}[Erro de digitação] Verifique novamente como usar o servidor!" + '\033[39m') Servidor import socket import threading from colorama import Fore, Back, Style IP = "" PORT = 4445 def handle_client(connection, address): print('\033[32m' + f"[Nova conexão] Endereço {address} conectado no servidor." + '\033[39m') connected = True while connected: message = connection.recv(1024).decode("utf-8") splitmessage = message.split(" ") new_message = "" for value in splitmessage: if(value != 'echo'): new_message += value + " " if message == 'quit': connected = False print(f"[{address}] {new_message}") if(connected == False): print('\033[31m' + f"Usuário {address} foi desconectado!" + '\033[39m') connection.send(new_message.encode("utf-8")) connection.close() print("[INICIANDO] Servidor está iniciando") server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((IP, PORT)) server.listen() print( '\033[36m' + f"[ESCUTANDO] Servidor está escutando" + '\033[39m') while True: connection, address = server.accept() thread = threading.Thread(target=handle_client, args=(connection, address)) thread.start() print( '\033[35m' + f"[CONEXÕES ATIVAS] {threading.activeCount() - 1}" + '\033[39m') 7) Testes Além do vídeo disponibilizado nos arquivos que eu enviei, resolvi dar uma complementada, e acabei por realizar 4 testes distintos (porque não deu tempo de fazer mais). O primeiro foi para testar o que acontece caso eu feche o servidor com um cliente conectado. No caso a primeira mensagem não tem resposta do servidor, porém continua conectado. Já na segunda mensagem temos um erro de BrokenPipeError. Isso acontece porque o processo de leitura (head) é finalizado e o processo de escrita (python) ainda tenta escrever, o que ocasiona em erro. O segundo foi para testar o que aconteceria caso eu conectasse o servidor com o IP de localhost em uma virtualbox que não está rodando o servidor. O resultado é que não conseguimos conectar nesse servidor, e ainda recebemos o erro de Connection Refused. Esse erro significa que, por qualquer motivo, o cliente não pode se conectar à porta no computador que está executando o script do servidor. O terceiro foi para testar o que aconteceria caso eu tentasse conectar no servidorcom uma porta diferente da que foi setada. O resultado foi o mesmo obtido no teste 2 (ConnectionRefusedError) e no caso de uma porta que não está entre o limite 0-65535 obtivemos como resposta o erro OverflowError. O quarto eu quis criar vários clientes para testar se o servidor continuaria apto a escutar todos eles. Acabei então por criar 30 e funcionou perfeitamente, imagino que provavelmente daria para ligar ainda mais clientes no servidor, mas é muito provável que tenha um limite (talvez ligado à memória RAM? Meu computador tem 32GB de RAM então só se eu fizesse um script eu conseguiria descobrir esse limite). Também é importante notar que se eu fechar a aba que estão esses terminais Todos eles estarão desconectados do servidor. 8) Referências: Vídeo que usei para aprender a fazer o NAT Network https://www.youtube.com/watch?v=vReAkOq-59I&t=180s&ab_channel=AlpineS ecurity Biblioteca usada do colorama https://pypi.org/project/colorama/ https://www.youtube.com/watch?v=vReAkOq-59I&t=180s&ab_channel=AlpineSecurity https://www.youtube.com/watch?v=vReAkOq-59I&t=180s&ab_channel=AlpineSecurity https://pypi.org/project/colorama/
Compartilhar