= Receita: Pequeno uso de sockets = Este é o primeiro programa que fiz em Python. Ele explora um pouco o uso de sockets. Quando fiz o programa enfrentei uma certa dificuldade em encontrar material explicando o uso de sockets para iniciantes, portanto o que consegui fazer é o que segue. Minha intenção com este CookBook é tentar ajudar os novos usuarios da linguagem e pedir ajuda aos mais experientes para desenvolver um programa mais otimizado e bem feito. Espero que isso sirva de aprendizado para todos. == Código == {{{ #!python import socket import sys class LenghtError(Exception): pass class RepeatedDigitsError(Exception): pass def testNum(num): """Funcao para testar se o número possui digitos repetidos ou se é maior que 4.""" if len(num) != 4: raise LenghtError for i in num: if num.count(i) > 1: raise RepeatedDigitsError class GameCon: """Classe para cuidar da conexao do jogo""" def __init__(self): self.sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM) def con(self, ip, port=1911): self.sock.connect((ip, port)) def waitCon(self, ip='', port=1911, l=1): self.sock.bind((ip, port)) self.sock.listen(l) (clientsocket, address) = self.sock.accept() self.sock = clientsocket def send(self, msg): sent = self.sock.send(msg) if sent == 0: raise BrokenCon, "socket connection broken" def receive(self, bytes): return self.sock.recv(bytes) def close(self): self.sock.close() class Senha: """Classe do jogo senha""" def __init__(self, myNum, hisNum): self.myNum = str(myNum) #Numero do cliente self.hisNum = str(hisNum) #Numero do server(adversario) def check(self, checkNum): """Metodo para checar o numero de bombas e tiros de um determinado numero em relacao ao self.hisNum(numero do adversrio)""" total = 0 #Total de numeros coicidentes bombs = 0 for a in checkNum: total+=self.hisNum.count(a) for i in xrange(4): if checkNum[i] == self.hisNum[i]: bombs+=1 shots = total - bombs return bombs, shots def sender(skt, pwd): """Funcao que recebe o numero a ser testado e o envia para o adversario e verifica vitoria""" while True: try: num = raw_input('Digite o numero a ser testado: ').strip() testNum(num) skt.send(num) break except LenghtError: print '!!\nO numero deve ter quatro digitos\n...' except RepeatedDigitsError: print '!!\nO numero nao pode ter digitos repetidos\n...' print 'Bombas: %s Tiros: %s' % pwd.check(num) if num == pwd.hisNum: # Se o numero que testei eh igual do # adversario, eu ganho print '\n\nVOCE GANHOU! Parabens :-)' skt.close() if raw_input('Jogar denovo? [s/n] ').startswith('s'): main() else: sys.exit() getter(skt, pwd) # Um metodo que chama o outro num loop # continuo, deve ser a pior solucao para # meu problema :-/ def getter(skt, pwd): """Funcao que recebe o numero tentado pelo adversrio, o imprime na tela e verifica derrota""" print '\nEsperando a escolha do adversario...' hisNum = skt.receive(4) print '::Ele chutou: %s\n' % hisNum if hisNum == pwd.myNum: print '\n\nVOCE PERDEU! :-(' skt.close() if raw_input('Jogar denovo? [s/n] ').startswith('s'): main() else: sys.exit() sender(skt, pwd) def main(): talker = GameCon() #Cria um objeto socket while True: print '1. Servidor\n2. Cliente' choice = input('Escolha: ') if choice == 1 or choice == 2: break if choice == 1: print 'Esperando conexao...' talker.waitCon() else: while True: ip = raw_input('Digite o IP do servidor: ').strip() try: talker.con(ip) break except: print 'Conexao nao aceita' while True: try: myNum = raw_input('Digite seu numero: ').strip() testNum(myNum) talker.send(myNum) hisNum = talker.receive(4) game = Senha(myNum, hisNum) break except LenghtError: print '!!\nO numero deve ter quatro digitos\n...' except RepeatedDigitsError: print '!!\nO numero nao pode ter digitos repetidos\n...' if choice == 1: sender(talker, game) else: getter(talker, game) if __name__ == '__main__': main() }}} == Explicação do jogo == Senha é um jogo a ser jogado por duas pessoas, os dois escolhem suas respectivas senhas (números de quatro digitos sem repetição de digito) e tentam adivinhar a do adversario. Para conseguir descobrir a senha do outro o jogador chuta um número qualquer e, se tiver acertado a posição de algum digito ele fez uma "bomba", se tiver acertado um digito mas não na posição correta ele fez um "tiro" (ex. sendo o número do adversário 1234, e o chute 3214, o jogador fez dois tiros e duas bombas). A versão do jogo na internet precisa que o chute seja alternado (cada hora um). Os dois jogadores tem em seu computador o número escolhido e o número do adversario, então a conexão existe apenas para saber quando é a vez de cada um jogar e enviar o número testado para o adversário poder saber quão perto esta da derrota (ou não). Creio que um metodo melhor seria que cada cliente recebesse o número a ser testado do adversário e retornasse a este o tanto de bombas e tiros acertados. Todavia, acho que já deu para pegar o espirito da coisa. Espero alterações no código e sugestões. ''Vamos lá pessoal. Eu sugeri que o Rafael colocasse esse jogo aqui para que todos venham aqui palpitar, sugerir mudanças, sugerir outros programas inteiro. Peço para que vocês não alterem o código original do Rafael e façam as suas modificações abaixo desta mensagem aqui. No final de tudo, eu vou coletar esses dados, acertar a formatação e tranformar num tutorial de criação de aplicações para iniciantes. O que acharam da idéia? -- OsvaldoSantanaNeto'' == Comentários == Ei cara... tipo... eu jah vi isso em varios códigos Python, mas eu faço diferente... no código acima, essas duas linhas: {{{ #!python if __name__ == '__main__': main() }}} chama a função principal do programa, ou seja, inicia o programa... eu, porém, depois de definir todo o programa coloco na ultima linha do código a chamada para a função main, ou seja, coloco somente: {{{ #!python main() }}} isso tah certo? queria saber como funciona essa variável {{{__name__}}} e tal... e queria saber se eh aconselhavel fazer como no código acima ou se tanto faz.... flw.. João Norberto de Souza Junior - Curitiba - PR ---- A maneira que você chama o {{{main()}}} funciona normalmente. Entretanto, é recomendado o uso da verificação {{{if __name__ == '__main__':}}} pelo seguinte motivo demonstrado abaixo: {{{ #!python # modulo.py - arquivo de modulo if __name__ == '__main__': print "Executado do arquivo..." print "Executado ao importar módulo: " + __name__ }}} Depois de gerado esse arquivo faça o seguinte: {{{ $ python modulo.py Executando do arquivo... Executado ao importar módulo: __main__ $ python >>> import modulo Executado ao importar o módulo: modulo >>> }}} Ou seja, quando você executa o arquivo diretamente com o interpretador Python ele coloca {{{__main__}}} dentro da variável {{{__name__}}}, já quando o módulo é importado ele coloca o nome do módulo nesta variável. Portanto esse {{{if}}} serve para evitar que o código seja executado quando o módulo é importado. -- OsvaldoSantanaNeto ---- Volta para CookBook. ---- RafaelAlmeida (aFlag)