Reputation: 33
I'm experimenting with communication via sockets in Python. I have a server.py-file and a client.py. The latter is asking for a user input and send this to the server. Depending on the user input, the server is playing 2 different sound. This works a single time but not for a second attempt.
I've put in some print(XYZ) lines to see where the programm is stopping. After sending the first message the "print("...")"-line of my server.py is no longer executed. So it looks like server_socket.accept() is no longer successful. Why is that?
This is server.py:
import socket
import winsound
fnameBeep = "beep.wav"
fnameBop = "bop.wav"
server_socket = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
server_addr = ("127.0.0.1", 1337)
server_socket.bind(server_addr)
server_socket.listen(1000)
while True:
print("waiting...")
(client_socket, addr) = server_socket.accept()
print("...")
msg = client_socket.recv(1024)
print(msg)
print("Received: " + str(msg, "utf8"))
if str(msg, "utf8") == '1':
winsound.PlaySound(fnameBeep, winsound.SND_FILENAME)
else:
winsound.PlaySound(fnameBop, winsound.SND_FILENAME)
This is client.py:
import socket
client_socket = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
server_addr = ("127.0.0.1", 1337)
print("Beep = 1; Bop = 2")
client_socket.connect(server_addr)
while True:
print('waiting ...')
UserInput = input('Your choice: ')
print('Sending: ' + UserInput)
client_socket.send(bytes(UserInput, "utf8"))
print('Sent!')
What is going wrong? the general communicaiton is working but I'd like to send a sequence of messages to the server.
Upvotes: 1
Views: 1825
Reputation: 73081
The first thing you'll want to do is move your accept()
call up to above the top of your while
loop -- as it is, your code is trying to accept a new TCP connection after each command, which I think it not what you wanted to do -- presumably you want to keep a single TCP connection open and receive multiple commands over that TCP connection instead.
The second issue is framing: the thing to remember about TCP is that it implements a raw stream of bytes, and doesn't do any fixed framing of messages on its own -- e.g. if you execute the following calls on the sending side:
client_socket.send("123")
client_socket.send("456")
client_socket.send("789")
... the on the receiving side, the server might see the following data-chunks returned from its subsequent recv() calls:
recv() call #1: 12345
recv() call #2: 67
recv() call #3: 89
... or, it might instead (depending on how the network is working, phase of the moon, etc) get the following:
recv() call #1: 1
recv() call #2: 2345678
recv() call #3: 9
or it might get all the sent data in a single call:
recv() call #1: 123456789
or it might even receive each byte via a separate call:
recv() call #1: 1
recv() call #2: 2
recv() call #3: 3
recv() call #4: 4
recv() call #5: 5
recv() call #6: 6
recv() call #7: 7
recv() call #8: 8
recv() call #9: 9
... or any other combination you can imagine.
So the question is, given the uncertainty of the data-chunking, how can your receiver know that your client intended to send ("file_name1.wav" and then "file_name2.wav") rather than just ("file_name1.wavfile_name.wav"), or ("file", "name1.wavfile", "name.wav"), or etc?
In order to parse the incoming TCP bytes unambiguously, the receiver has to know how they are framed. For a simple program like yours, the framing logic could be straightforward -- e.g. just declare a rule that each string will have a newline character at the end. Then your server can simply keep receiving bytes (and adding them to the end of a string) until it sees a newline byte, at which point it knows it has received a full user-command, so it can at that point handle that command, then remove all of the string (up to and including the newline character) before continuing its parsing for the next string.
Another way to do it is to have the sender include a short (fixed-length) header before each command indicating the number of bytes that the receiver should expect to see in the next command. Then the server can read the header (because the header is fixed-length, the server will know how many bytes it needs to read before it has the full header to look at), and then read that-many bytes, then handle the command, then repeat.
Upvotes: 1