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)
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.
– Leonardo Burle