How to Create a communication between two clients via server using socket

Asked

Viewed 5,801 times

2

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 he must have received a message. PS: In order for it to work you have to run the server code first once, and then the client twice, and I’m using Windows.

1 answer

3


this is the moment you find out because people don’t do that ordinarily. sending a test message via sockets is simple - with code like the above. have 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 the calls recv socket, etc...

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

In short, you have a lot of work ahead of you, and you will need to learn a lot while you do that. If you’re really into it, it’ll be worth it in the end, but it’s not just one or two lines of code missing there.

So, just to give a few hints 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 responds to the input will you execute the method recv, and only then receive a message (if you will receive one). On the other hand, after input, while no message from the socket arrives, the program will stand still waiting for the return of the method s.recv.

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

If you do your program in graphic mode, for example, with "Tkinter", you will already solve 80% of the problems: you will have a text area for the chat, and a text input, in a separate control, to write the message. You won’t have trouble mixing what the person is typing with incoming messages, and he controls the incoming text asynchronously - plus having a window, you can invite your friends and relatives to try out your program that won’t just be on the terminal.

In text mode you have to do everything "in hand" even. The easiest way to start, but not the "right way to end" and perhaps not the simplest, will be to use threads. A "thread". (For a more correct form a", see the module selectors from the standard Python library. The example you have there is for sockets, but you can register sys.stdin to be notified when the user enters 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 don’t explicitly use "threads," they will emulate your behavior in some way.

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

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

Your "multi-threaded client" could look something like this: (Python 3-Alias, switch to Python 3. Python 2 is from last millennium, what are you doing with it?). The only difference is that it is necessary to decode the text to bytes when sending it to the socket, and vice versa. In addition to the wiser "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)
  • 1

    Thank you very much for your explanation. I was able to solve this problem exactly the way you mentioned, using threads, one to monitor the arrival of the message and the other to control the sending of them. Actually this program is a work of college that I am doing and it is by determination of the teacher that I use Python 2. I am also using a database, with sqlite, on the server to make a system of registration, authentication, etc. Indeed, Tkinter will help a lot, I’ll use it soon. Again, thank you so much for the reply.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.