''' ------------------------------------ HEADER ------------------------------------ Autores: Michel Brasil Cordeiro (GRR20172663) Vinícius Teixeira Vieira dos Santos (GRR20186716) Descrição: Arquivo contendo a implementação de um servidor que responde requisições via socket para verificar a temperatura na região determinada por seu ID e descita no arquivo lib.py. As temperaturas são obtidas pela internet, fazendo um request para a wttr.in (https://github.com/chubin/wttr.in) e tratando o resultado. Requisitos de uso: É necessário iniciar o servidor com um argumento (que seja um inteiro de valor maior ou igual a 0 e menor que 3) que servirá para designar seu ID próprio. Caso o argumento não seja passado ou não seja do tipo inteiro, o servidor assumirá que o servidor usará o ID 0. Ex de execução: > python3 servidor.py 2 Última atualização: 23/04/2022 -------------------------------------------------------------------------------- ''' import re import requests import socket import sys from lib import * # variáveis do servidor HOST = "127.0.0.1" # loopback (localhost) PORT = 8000 # Porta padrão ID_SERVER = None # ID do servidor LOCAL_SERVER= None # Local em que está localizado o servidor LINK = None # Link do servidor para obter a temperatura """ Ajusta as variáveis do servidor (porta para conexão, ID do servidor, local em que o servidor estará e link para requisição de temperatura) com base no id_key passado e utilizando os valores definidos em lib.py, além de impressões na tela como logs. :param id_key: ID que será utilizado pelo servidor. Caso seja menor que 0 e maior que 2, assume-se que o servidor urilizará o valor 0. :return: Esta função não possui retorno """ def getServerInfo(id_key): global ID_SERVER global LOCAL_SERVER global LINK global PORT if ( id_key >= 0 and id_key < 3): ID_SERVER = id_key else: print("ID do servidor não disponível. Assumindo id 0.") ID_SERVER = 0 options = { 0: (PORT_SERVER_0, PLACE_0, LINK_0), 1: (PORT_SERVER_1, PLACE_1, LINK_1), 2: (PORT_SERVER_2, PLACE_2, LINK_2) } PORT, LOCAL_SERVER, LINK = options.get(id_key, 0) """ Gera uma mensagem resposta com base na message passada por parâmetro e impressões na tela como logs. Caso message seja um pedido para que a conexão do socket seja fechada, retorna None. :param message: Mensagem do tipo Message a ser tratada. :return: None caso seja um pedido para fechar a conexão. Caso contrário, retornará a mensagem do tipo Message a ser enviada em resposta. """ def processMessage(message): # double-check para verificar se a mensagem que chegou é para este servidor if (message.server_id != ID_SERVER): print("Mensagem recebida com id errado.") return Message(ID_SERVER, MSG_ERR, 0) if (message.message_type == MSG_REQ): temp = getTemp() if (temp == None): return Message(ID_SERVER, MSG_ERR, 0) return Message(ID_SERVER, MSG_RESP, temp) if (message.message_type == MSG_END): print("Pedido para fechar a conexão recebido. Fechando socket do servidor {}.".format(ID_SERVER)) return None """ Busca a temperatura do local definido pela variável global LOCAL_SERVER por requisição via internet utilizando a variável global LINK e impressões na tela como logs. Caso a requisição seja executada, retorna o valor inteiro da temperatura em graus Celsius. Caso contrário retornará None. :return: Número inteiro contendo a temperatura em Celsius caso a requisição seja bem-sucedida. None caso contrário. """ def getTemp(): print("Pedido da temperatura atual recebido.") try: res = requests.get(LINK) except: print("Erro ao obter temperatura atual. Sem conexão de internet.") return None # Caso a localização não exista ou os servidores do wttr.in estejam fora de ar (https://github.com/chubin/wttr.in/issues/638) if "Unknown location" in res.text: print("Erro ao obter temperatura atual. Servidores fora do ar ou localização não encontrada") return None temp = int(re.findall('[\+\-]?[0-9]+', res.text)[0]) print("Temperatura atual: {}°C".format(temp)) return temp """ Função main que será executada pelo servidor """ def main(): # Set de variáveis do servidor if(len(sys.argv) > 1): getServerInfo(int(sys.argv[1])) else: print("ID do servidor não encontrado. Assumindo 0.") getServerInfo(0) # estabelece conexão via socket connected = False with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: # Abre a conexão socket print("Abrindo conexão com a tabela cache...") s.bind((HOST, PORT)) s.listen(0) conn, addr = s.accept() print("Conexão estabelecida!") # faz a leitura de mensagens(de tamanho de 12 Bytes) with conn: while True: data = conn.recv(12) # leitura de dados no socket (bloqueante) print("Mensagem recebida.") msg_rcv = bytes_to_message(data) msg = processMessage(msg_rcv) if (msg == None): # Fecha conexão socket conn.close() break bytes_sent = conn.send(msg.message_to_bytes()) # verifica o tamanho dos bytes enviados para verificar se a resposta # foi enviada corretamente if (bytes_sent != 12): print("\n\nErro ao enviar mensagem!\n\n") print("Conexão socket fechada. Finzalizando execução.") if __name__ == "__main__": main()