Chat com socket e telnet
É incrível o que faz a necessidade, hoje tivemos queda de sinal por parte da Net Virtua (não havia sido resolvido até a hora de eu ir embora), porém, meus amigos e eu temos o hábito de falar besteiras dos mais diversos tipos por mensageiros web, como GTalk, e a falta de internet nos fez recorrer a outros recursos pra comunicação[1] como seqüências de pipelines com arquivos e até mesmo apelamos para o "gdialog"[2].
O problema dessas soluções era que ficava chato digitar os comandos, e tudo sempre ficava centralizado em uma única maquina, não havia nenhuma comunicação entre os computadores que não fossem os terminais SSH[3], insatisfeito com isso e querendo relaxar um pouco do stress do projeto em que estava resolvi aplicar meus conhecimentos sobre Python e implementar um servidor de chat simples, que recebesse uma mensagem de um cliente e distribuísse entre os demais.
Então abri 2 terminais, em um estava o "vi" (com syntax highlight on por pura frescura) e no outro o "pydoc socket"[4], foi então que escrevi um programa como esse[5]:
[python]
#!/usr/bin/env python
"""
Use this server to chat with others people in a telnet client, just run this
script and connect with telnet:
$ telnet server 26123
"""
import sys # Used to get IP and port
import socket # Basic import
from threading import Thread # We use threads instead forks, just to simplify (oO?)
all_clients = []
def usage():
print """Usage:
chat.py host port
- host is your ip
- port is the port to listen, this MUST be integer
"""
class Client(Thread):
"""When a client connect this class is initialized and care to send texts
received to another clients"""
def __init__(self, client):
Thread.__init__(self)
self.socket = client[0] # Socket to client
self.name = '%s:%d'%client[1] # "Name" of the client
def run(self):
while True: # Break only when a client type "quit"
# Wait for some text (currently the max lenght supported is 1k)
buff = self.socket.recv(1024)
if buff.strip() == 'quit':
self.socket.close()
break # Exit when break
# Send the incoming text to all clients
for index, client in enumerate(all_clients):
if client.name == self.name:
continue # We don't want receive our own text, right?
try:
# Send the text
client.socket.sendall('[%s] => %s'%(client.name, buff))
except socket.error, e:
# If failed to send, remove from list
del all_clients[index]
if __name__ == "__main__":
if len(sys.argv) < 3:
usage()
exit(1)
host, port = sys.argv[1:3] # How to get your own IP is to other post
sock = socket.socket() # Initialize the socket
try:
sock.bind((host, int(port)))
except ValueError,e:
usage()
exit(1)
sock.listen(1) # Listen the address
while True:
all_clients.append(
Client(sock.accept())
) # Accept a new client, create the Client instance and update all_clients
all_clients[-1].start() # Start the thread
__all__ = ['all_clients','Client']
[/python]
Como você pode ver é um script simples, compacto (65 linhas contando com comentários) e eficiente, pois com ele pudemos finalmente voltar a conversar[1] sobre as besteiras fúteis do dia-a-dia.
Execução:
Seu uso é muito simples, apenas salve-o como "chat.py" e execute-o no console:
python chat.py 192.168.0.1 21345
Lembre-se de alterar `192.168.0.1` para seu IP e `21345` para a porta que você quiser usar
Você também pode adicionar permissão de execução à ele e executa-lo como aplicativo normal:
chmod +x chat.py
./chat.py
Conectando-se:
Pra se conectar no servidor abra uma outra aba/terminal e rode:
telnet 192.168.0.1 21234
E pronto, com isso você já tem um servidor de chat interno para falar a besteira que quiser com seus amigos.
Bugs:
Bom, existem alguns pontos óbvios pra quem já programou para terminal, como por exemplo, se você estiver digitando uma mensagem e receber outra, seu texto vai ficar quebrado no meio e o texto recebido vai aparecer logo após o que você está digitando, isso poderia ser resolvido escrevendo o cliente com ncurses, mas isso é assunto pra outro post
Outro ponto é que o servidor apenas suporta buffers de 1KB, que poderia ser resolvido com um `for` até que a entrada de dados esteja limpa (? não sei se funcionaria).
Notas:
[1] - Sim, comunicação verbal é mais eficiente, mas não era o caso, pois apenas atrapalharia o trabalho dos outros
[2] - Gera uma caixa de dialogo no meio da tela, mas não é muito eficiente visto que não haverá um histórico e pode (e irá) atrapalhar quem está programando
[3] - Offtopic: Se um dia você precisar usar Linux e Windows na mesma máquina ao mesmo tempo pelo VMWare, não caia na bobagem de aproveitar que o Windows já está instalado e colocar uma máquina virtual com Linux, eu fiz isso e me arrependo amargamente, é melhor rodar o Windows a partir do Linux do que o Linux a partir do Windows
[4] - Sim, também sou humano e preciso ler a documentação pra fazer as coisas funcionar melhor
[5] - Não é exatamente esse porque (como já disse) estávamos sem internet e eu não podia enviar o arquivo pro meu email
Deixe um comentário |

