How to Create a Communication Between Two Clients via Server Using Socket

1
import socket
from threading import Thread
def client(h, p):

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # IPv4,tipo de socket
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    while True:
        try:
            s.connect((h, p))
            break
        except Exception as e:
            pass

    print "Conectou"
    msg = ''
    while msg != "Fim":
        msg = raw_input("Entre com a mensagem: ")
        s.sendall(msg)# Envia dados
        var = s.recv(1024)
        print var
    s.close()  # Termina conexao
    print "Fechou a conexao"
if __name__ == '__main__':

h2 = raw_input("Entre com o IP do servidor remoto:")
port2= input("Entre com a porta do servidor remoto:")
client(h2,port2)


# Criando o codigo do servidor
import socket
from threading import Thread
L=[]

def ConversaSimultanea(a,b):
    mensagem = ""
    while mensagem != "Fim":
        print "entrou no loop da conversa"
        mensagem = L[a].recv(5000)
        if not mensagem:
            break
        L[b].sendall(mensagem)
    conn.close()

#h = raw_input("Entre com o IP do Servidor local: ")
#port = input("Entre com a Porta do Servidor local: ")

h = '127.0.0.1'
port = int('40000')

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # IPv4,tipo de socket
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print "chegou ate aqui"
s.bind((h, port))  # liga o socket com IP e porta
s.listen(1)  # espera chegar pacotes na porta especificada
print "server escutando"

for i in range(2):
    print "esperando o primeiro cliente conectar-se"
    conn, addr = s.accept()  # as variaveis conn a addr sao preenchidas pela funcao accept
    L.append(conn)
    print "conectei e appendei o primeiro cliente"
t1 = Thread(target=ConversaSimultanea, args=(1,0,)).start()
t2 = Thread(target=ConversaSimultanea, args=(0,1,)).start()

These two codes are working in part. The problem I'm having is that for a client to send a message it must have received a message. PS: In order for it to work it has to run the server code first once, and then the client's twice, and I'm using Windows.

    
asked by anonymous 13.11.2017 / 15:42

1 answer

0

This is the moment when you discover why people do not do this ordinarily. sending a test message via sockets is simple - with code like the one above. having a complete implementation of a chat depends on several other things: it is a complete system, you will need to have a separate "main loop" in thread or with async instead of locking in% socket calls, etc ...

Just look at your code and see that it does exactly what you ordered - and then realize that it can not even be a generic chat: your code on the server is "hardcoded" (that is, fixed on program code) to just send messages from cleint "a" to client "b", but it will never do otherwise.

In short, there is plenty of work ahead, and you will need to learn a lot while doing this. If you really are up for it, it will be worth it at the end, but it's not just one or two lines of code missing.

So, just to give some clues as to which way to go, but it would be close to a book to explain everything. So in code like:

while msg != "Fim":
    msg = raw_input("Entre com a mensagem: ")
    s.sendall(msg)# Envia dados
    var = s.recv(1024)
    print var

It is easy to see that only after someone answers the input will you execute the recv method, and only then receive a message (if any). On the other hand, after the input, until no message arrives from the socket, the program will be stopped waiting for the return of the recv method.

The only way to solve this kind of thing is to have a control "main loop" that does not directly call the blocking functions: that of receiving data from the socket and receiving data from the keyboard.

If you run your program in graphical mode, for example with "tkinter", you will solve 80% of the problems: you will have a text area for the chat, a text entry, a separate control, to write the message. There will be no mixing problem that the person is typing with messages that have arrived, and he controls the text input asynchronously - besides having a window, you can invite your friends and relatives to try out your program that will not stay only at the terminal.

In text mode you have to do everything "in the hand" yourself. The easiest way to start, but not the "most correct to finish" and maybe not the simplest, will be using threads. A "thread." (For a more correct form, see the s.recv module of the default Python library. The example you have is there for sockets, but you can register selectors to be notified when the user types something, before having to call the input)

Why am I talking about thread then? Because it's a concept you have to understand, to better understand large systems later - even if they do not explicitly use threads, they will emulate their behavior in some way.

Each "thread" will be like a separate program, which runs "at the same time" as your main program. This way, you can have a thread waiting for the "input", a thread waiting for the "recv", and a third prinipal thread that could print everything.

To communicate data between threads, you can use a queue of type threading.Queue (), but in the case of this first simpler version, you can have both threads doing "everything they need" directly, without switching between them. (A schizophrenic chat program);

Your "multi-threaded client" could look something like this: (Python 3- Alias, switch to Python 3. Python 2 is from the last millennium, what are you doing with it?). The only difference is that it is necessary to decode the text to bytes by sending it to the socket, and vice versa. In addition to more sensible "print" and "input".

import socket
from threading import Thread
import time

def recebe_mensagens(socket_):
    while True:
        msg = socket_.recv(1024)
        if not(len(msg)):
            break
        print(msg.decode("utf-8"))
    print("Conexão com o servidor encerrada")


def envia_mensagens(socket_):
    while True:
        msg = input("Msg> ")
        try:
            socket_.sendall(msg.encode("utf-8"))
        except socket.error:
            break
        if msg.lower() == "fim":
            socket_.close()
            break
    print("Envio de mensagens encerrado!")


def client(h, p):

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # IPv4,tipo de socket
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    envia = Thread(target=envia_mensagens, args=(s,))
    recebe = Thread(target=recebe_mensagens, args=(s,))

    envia.start()
    recebe.start()

    while threang.active_count() > 1:
        # pausa de 0.1 segundo,
        # Evita que a CPU fique processando a comparação acima sem parar.
        time.sleep(0.1)
    print("Programa encerrado")


if __name__ == '__main__':
    h = input("Host do servidor: ")
    p = input("Porta do servidor: ")
    client(h, p)
    
14.11.2017 / 14:24