2
respostas

Programação com cliente e servidor com Threads: Como conseguir inúmeras trocas de dados por cliente e inúmeros clientes simultaneamente?

O cliente:

from socket import *


serverHost = 'localhost'
serverPort = 8884

# Menssagem a ser mandada codificada em bytes
menssagem = [b'Ola mundo da internet!']

# Criamos o socket e o conectamos ao servidor
sockobj = socket(AF_INET, SOCK_STREAM)
sockobj.connect((serverHost, serverPort))

# Mandamos a menssagem linha por linha
for linha in menssagem:
    sockobj.send(linha)

    # Depois de mandar uma linha esperamos uma resposta
    # do servidor
    data = sockobj.recv(1024)
    print('Cliente recebeu:', data)

# Fechamos a conexão
sockobj.close()

O servidor:

import socket

from threading import Thread



def Servidor():

    servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    ip = "0.0.0.0"
    porta = 8884

    servidor.bind((ip, porta))

    servidor.listen(5)

    socket_client, adddress = servidor.accept()

    while True:

        dados = socket_client.recv(2048)

        print("Cliente: ", dados.decode("utf8"))
        msg = input("Servidor: ")
        enviados = socket_client.send(msg.encode("utf8"))

    servidor.close()



MeuServidor = Thread(target=Servidor,args=[])

MeuServidor.start()



Problema: Só existe 1 troca de dados por cliente conectado! Após a primeira troca de dados, a conexão é encerrada!

Como modificar o servidor de forma a possibilitar inúmeras trocas de dados, até o cliente resolver encerrar a conexão?

Problema2: O servidor só lida com 1 cliente por vez: Como torná-lo capaz de lidar com vários clientes simultaneamente?
2 respostas

Oi, Edson! Tudo bem? Legal ver alguém se interessando por sockets, não é tão comum ;).

Para a primeira questão de seu programa só estar mandando uma mensagem e fechando o problema está no seu código cliente. Ele está mandando todas as mensagens da lista menssagem e, depois, fechando a conexão. Precisamos adicionar um loop, mais ou menos dessa forma:

conexao_aberta = True
while conexao_aberta:
    mensagem = input('Digite sua mensagem: ')
    if mensagem == '/sair':
        conexao_aberta = False
    sockobj.send(mensagem.encode())
    data = sockobj.recv(1024).decode()
    print('Cliente recebeu: ' + data)

sockobj.close()

E pra fechar direitinho no servidor também, você adiciona algo como:

conexao_aberta = True
while conexao_aberta:
    dados = socket_client.recv(2048).decode()
    if dados == '/sair':
        conexao_aberta = False
    print('Cliente: ' + dados)
    msg = input('Servidor: ').encode()
    socket_client.send(msg)

socket_client.close()
servidor.close()

Para a segunda questão, aí entramos em algumas complicações de threading que não cabem muito detalhamento aqui. De um jeito simples, você poderia fazer um loop while criando uma thread para cada cliente, como dessa forma:

import socket
from threading import Thread

def Servidor(socket_client, addr):
    conexao_aberta = True
    while conexao_aberta:
        dados = socket_client.recv(2048).decode()
        if dados == '/sair':
            conexao_aberta = False
        print('Cliente ({}): {}'.format(addr[1], dados))
        msg = input('Servidor ({}): '.format(addr[1])).encode()
        socket_client.send(msg)

    socket_client.close()

servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip = "0.0.0.0"
porta = 8884
servidor.bind((ip, porta))
servidor.listen(2)

while True:
    socket_client, addr = servidor.accept()
    MeuServidor = Thread(target=Servidor,args=(socket_client, addr))
    MeuServidor.start()

Se você testar esse código, vai perceber que ainda temos alguns problemas, como se dois clientes mandarem uma mensagem para o servidor antes dele responder uma delas, ou que o socket do servidor não é fechado. Vou deixar esses problemas pra você pesquisar mais sobre sockets e threading e tentar resolver ;). Lembrando que não é um assunto trivial, entrando em tópicos avançados que realmente podem fazer a gente bater a cabeça pra resolver! Então leve seu tempo pra ir estudando isso, se te interessa!

Abraços, Edson!

@Yan Orestes: Obrigado! Eu estou tentando aprender esses assuntos! Obrigado pela resposta. Vou estudar seguindo as suas sugestões e volto aqui para perguntar! Muito obrigado!