a conexao e terminada. Vamos ver o programa completo e discutir parte por parte.import asyncioimport timefrom common import *class EchoServer(asyncio.streams.FlowControlMixin): ativas = 0 def connection_made(self, transporte): peername = transporte.get_extra_info('peername') print('Conexao de {}'.format(peername)) EchoServer.ativas+=1 print("Conexoes ativas: {}".format(EchoServer.ativas)) self.transporte = transporte self.leitor = asyncio.StreamReader() self.leitor.set_transport(self.transporte) self.escritor = asyncio.StreamWriter(transport=self.transporte, protocol=self, reader=self.leitor, loop=asyncio.get_event_loop()) asyncio.async(self.gerencia()) @asyncio.coroutine def gerencia(self): while True: dados = yield from self.leitor.readline() self.escritor.write(strToByte(time.strftime("%c")+"\r\n")) yield from self.escritor.drain() comando = byteToStr(dados).strip().lower() if(comando == "sair"): self.transporte.close() return def connection_lost(self, exp): EchoServer.ativas-=1 print("Conexoes ativas: {}".format(EchoServer.ativas)) super().connection_lost(exp) def data_received(self, dados): print('data received: {0}'.format(byteToHex(dados))) print(' received: {0}'.format(strPrintable(dados))) print(' string: {0}'.format(byteToStr(dados))) self.leitor.feed_data(dados) loop = asyncio.get_event_loop()coro = loop.create_server(EchoServer, '127.0.0.1', 8888)servidor = loop.run_until_complete(coro)print('Escutando {}'.format(servidor.sockets[0].getsockname()))try: loop.run_forever()except KeyboardInterrupt: print("exit")finally: servidor.close() loop.close()A classe EchoServer herda de uma classe fornecida em asyncio.streams, chamada FlowControlMixin. A classe FlowControlMixin e por sua vez derivada de Protocols, tambem fornecida pelo modulo asyncio. A ideia desta classe e implementar um protocol factory, ou seja, um construtor de instancias responsaveis pela implementacao da gestao de cada nova conexao. Um protocolo normal, precisa herdar apenas de Protocols, mas para utilizar alguns metodos para leitura buferizada de linhas, especialmente o write.drain que veremos logo apos, a implementacao contida em FlowControlMixin e interessante.Aproveitamos a nova classe para contar o numero de conexoes ativas. Cada nova conexao recebida por nosso servidor TCP/IP chama o construtor de nossa classe e o metodo connection_made, passando o transporte (entenda como o socket ja conectado) como parametro.Utilizando o parametro transporte, chamamos o metodo get_extra_info('peername') para obter o endereco do cliente que acabou de se conectar ao servidor. Logo em seguida, incrementamos o numero de conexoes. Veja que como o codigo que roda no loop de eventos nao e multi-threaded, nao precisamos de locks ou de outros mecanismos de controle, ja que apenas uma funcao roda a cada vez. O resto do metodo connection_made prepara as instancias do leitor e do escritor, objetos das classes StreamReader e StreamWriter respectivamente. Estes objetos vao fornecer corotinas uteis para ler e escrever os dados de forma nao bloqueante. Veja que passamos transporte tanto para o escritor quanto para o leitor e que uma serie de parametros sao necessarios para a inicializacao do escritor.No fim de connection_made, usamos a funcao asyncio.async para iniciar o processamento da corotina self.gerencia, dentro do loop de eventos. Veja que o metodo gerencia foi marcado com o decorador @asyncio.coroutine.O metodo gerencia contem uma estrutura de repeticao while que espera uma linha do cliente. Veja que utilizamos yield from para suspender a execucao de gerencia enquanto self.leitor.readline() nao terminar. Neste ponto, a execucao volta para o loop de eventos e retorna apenas quando self.leitor.readline() contem uma linha enviada pelo cliente ou caso uma excecao tenha ocorrido. O uso do yield from e fundamental, pois caso o readline() esperasse o cliente enviar a linha para continuar a execucao, todo o loop de eventos seria bloqueado. Como o uso do yield from, a execucao volta para o loop que e livre para executar outros metodos e outras corotinas. O objetivo e nao fazer o computador esperar por dados ou resultados que demoram muito tempo (ou um tempo desconhecido, possivelmente longo, para retornar). Outra