I copied the echo server example from the python documentation and it's working fine. But when I edit the code, so it wont send the data back to the client, the socket.recv() method doesn't return when it's called the second time.
import socket
HOST = ''
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(b'ok')
conn.close()
In the original version from the python documentation the while loop is slightly different:
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(data)
Client's code:
import socket
HOST = 'localhost'
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
data = s.recv(1024)
s.close()
print('Received', repr(data))
TCP sockets are streams of data. There is no one-to-one correlation between send calls on one side and receive calls on the other. There is a higher level correlation based on the protocol you implement. In the original code, the rule was that the server would send exactly what it received until the client closed the incoming side of the connection. Then the server closed the socket.
With your change, the rules changed. Now the server keeps receiving and discarding data until the client closes the incoming side of the connection. Then the server sends "ok" and closes the socket.
A client using the first rule hangs because its expecting data before it closes the socket. If it wants to work with this new server rule, it has to close its outgoing side of the socket to tell the server its done, and then it can get the return data.
I've updated the client and server to shutdown parts of the connection and also have the client do multiple recv's in case the incoming data is fragmented. Less complete implementations seem to work for small payloads because you are unlikely to get fragmentation, but break horribly in real production code.
server
import socket
HOST = ''
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(b'ok')
conn.shutdown(socket.SHUT_WR)
conn.close()
client
import socket
HOST = 'localhost'
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
s.shutdown(socket.SHUT_WR)
data = b''
while True:
buf = s.recv(1024)
if not buf:
break
data += buf
s.close()
print('Received', repr(data))
The number of receive and send operations have to match because they are blocking. This is the flow diagram for your code:
Server listen
Client connect
Server receive (this waits until a message arrives at the server) [1]
Client send 'Hello world' (received by [1])
Server receive (because there was data received) [2]
Client receive [3]
Because the server and the client are blocked now, no program can continue any further.
The fix would be to remove the client's receive call because you removed the server's send call.
Related
I have this python server code here, which is waiting to receive a message digest and an encrypted message from a python client.
Clientside socket:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s=socket.socket()
s.connect((HOST, PORT))
s.sendall(transmit)
Server Side:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
print("\n Server is listing on port :", PORT, "\n")
fragments = []
#Execution stops here
with conn:
print(f"Connected by {addr}")
while True:
chunk = s.recv(4096)
if not chunk:
break
fragments.append(chunk)
arr = 'b'.join(fragments)
#Test to see if the array was being populated
print(arr[0])
I have tried the methods this stackOF post here, specifically above is the provided list method implementation as my client is sending a "packet" of information as a list encoded as a string
packet = [signeddigest, ciphertext]
transmit = str(packet)
transmit = transmit.encode()
s.sendall(transmit)
I have tested my client code on a different server codebase with the same localhost and port number, and that server was receiving the information, so there's something I'm missing in the server side.
The output from the test server was
File [b'HT\xb0\x00~f\xde\xc8G)\xaf*\xcc\x90\xac\xca\x124\x7f\xa0\xaa\ requested from ('127.0.0.1', 49817)
That "file" is the encoded string sent from my client to the test server. So I'm confident there's something wrong with my server implementation.
Further information:
When I run the server it listens, then I run the client.
python ClientTest.py
Please enter the message to send
Then the server side immediately closes the connection
line 23, in
chunk = s.recv(4096) OSError: [WinError 10057] A request to send or receive data was disallowed because the socket is not connected and
(when sending on a datagram socket using a sendto call) no address was
supplied
You have a number of inconsistencies in your code:
while True:
chunk = s.recv(4096) # should be conn.recv(4096)
if not chunk:
break
fragments.append(chunk) # misaligned: you only append the empty chunk
arr = 'b'.join(fragments) # 'b' is an unicode string. You want b''
After fixing that to:
while True:
chunk = conn.recv(4096)
if not chunk:
break
fragments.append(chunk)
arr = b''.join(fragments)
arr will receive the sent data as soon as the client uses close or shutdown on its side of the socket.
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
conn is the connected socket, s is the listener socket.
chunk = s.recv(4096)
The error you get is because you are trying to read from the listener socket s, not from the connected socket conn:
line 23, in chunk = s.recv(4096) ... A request to send or receive data was disallowed because the socket is not connected ...
I'm new to python programming. I want to create a simple TCP server working with an esp32. The idea of this is to send command data = '{\"accel\",\"gyro\",\"time\":1}' to esp32 via socket and then wait around 10ms for reply from esp32. I tried many examples but nothing works. ESP32 gets my message from this program but I can't receive message from esp32.
import socket
# bind all IP address
HOST = '192.168.137.93'
# Listen on Port
PORT = 56606
#Size of receive buffer
localhost=('0.0.0.0', 56606)
BUFFER_SIZE = 1024
# Create a TCP/IP socket
data = '{\"accel\",\"gyro\",\"time\":1}'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the host and port
s.connect((HOST, PORT))
# send data to server
s.send(bytearray(data, 'utf-8'))
s.serve_forever()
print('Listen for incoming connections')
sock.listen(1)
while True:
client, addr = s.accept()
while True:
content = client.recv(1024)
if len(content) ==0:
break
else:
print(content)
print("Closing connection")
client.close()
I tried more and tried to use other code(see below). Now I get message back but on other port(I can track it by wireshark)
import socket
# Ip of local host
HOST = '192.168.137.93'
# Connect to Port
PORT = 56606
#Size of send buffer
BUFFER_SIZE = 4096
# data to sent to server
message = '{\"accel\",\"gyro\",\"time\":1}'
# Create a TCP/IP socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to server
s.connect((HOST, PORT))
# send data to server
s.send(bytearray(message, 'utf-8'))
# Receive response from server
data = ""
while len(data) < len(message):
data = s.recv(BUFFER_SIZE)
# Close connection
print ('Server to Client: ' , data)
s.close()
I don't use both of these codes together.
Any hints?
I want to set up a simple echo server that just echoes back whatever the client sends to it. However, currently the server disconnects (the server socket closes) after it echoes back the first client message. I want to be able to "chat" continuously with the server, where the server just echoes back several consecutive messages I send without disconnecting; e.g.:
"Hi there!"
"Echoing: Hi there!"
"How are you?"
"Echoing: How are you?"
"Cheers!"
"Echoing: Cheers!"
etc.
Currently I have the following code:
server.py:
import socket
HOST = '127.0.0.1'
PORT = 5000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
client.py:
import socket
HOST = '127.0.0.1'
PORT = 5000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
data = s.recv(1024)
print('Echoing: ', repr(data))
The server, however, disconnects after it echoes back the first client message (probably because of the if not data: break statement).
P.S. I'd appreciate any additional explanations which might be necessary - this example has educational purposes, so I'm not (only) after getting the code running.
Thanks!
server.py:
import socket
HOST = '127.0.0.1'
PORT = 5000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
while True:
data = conn.recv(1024)
if data.decode() == "bye":
break
conn.sendall(data)
conn, addr = s.accept()
I will show you the code I created then talk you through it:
Server:
import socket
HOST = '127.0.0.1'
PORT = 5000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
while True:
data = conn.recv(1024)
conn.sendall(data)
For the server I removed:
if not data:
break
It simply wasn't working for me. If you know your message is going to be less than the 1024 bytes( which here it is) it's unnecessary. But if you want a longer message change that value to a bigger number to accommodate. So yes you were right in suspecting it was that line.
Client:
import socket
HOST = '127.0.0.1'
PORT = 5000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
print("Connected")
while True:
print("Sending data")
s.sendall(b'Hello, world')
print("Recieving data")
data = s.recv(1024)
print('Echoing: ', repr(data))
For the client side I just added the send and receive process into a loop.
Things to note:
This only works for me when run through the terminal, I don't know if you know how to do that so sorry if you do, here's a link explaining:
https://www.wikihow.com/Use-Windows-Command-Prompt-to-Run-a-Python-File
I assumed you use Windows.
You will need to follow the process for both your client.py programme and server.py programme. Make sure you run the server.py programme first.
This will cause an infinite loop of sending and receiving. Press Ctrl+C to terminate.
I hope this solves your problem and you can edit the code accordingly. Any further problems please do comment and I'll try to get back to you.
Maybe use sleep instead of break
if not data:
time.sleep(1)
continue
You have to import time module for this.
Im trying to send a messages from the server to the client
I tried deleting the .close and puting a while loop on print but it still doesn't won't to work
Client
import socket
s = socket.socket()
host = socket.gethostname()
port = 12345
s.connect((host, port))
while True:
print (s.recv(1024))
Server
import socket
s = socket.socket()
host = socket.gethostname()
port = 12345
s.bind((host, port))
s.listen(5)
while True:
c, addr = s.accept()
print ('Got connection from', addr)
x = str(input("ënter a message"))
data = x.encode()
c.send(data)
I expect the output to be 2 messages from the server but it is only sending 1 and then closing the connection
Switch your accept and while True: lines. Once you accept a connection, keep sending on the same connection.
Note that TCP is a streaming protocol. There is no concept of "messages", but just a bunch of bytes. If you send fast enough, such as:
c.send(b'abc')
c.send(b'def')
then recv(1024) could receive b'abcdef'. For more complex communication, you'll have to define a protocol and buffer recv until you are sure you have a complete message. A simple way in this case is read until you find a newline, or send a byte (or more) indicating the size of the total message before sending the actual message.
I'm leanring how sockets work and trying to do some simple things.
My client is NOT sending anything to the server, and the server will not receive anything. But the problem is that the server socket will be always waiting for nothing. I want it to do something else if there is no available coming data from the client side. The if statement does not help end its waiting.
Server.py:
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
hostname = socket.gethostname()
host = socket.gethostbyname(hostname)
port = 9090
server.bind((host, port))
server.listen(10)
con, addr = server.accept()
msg = con.recv(2048)
if not msg:
con.send('hello world'.encode('utf-8'))
con.close()
server.close()
else:
con.send('hi Client I received it'.encode('utf-8'))
con.close()
server.close()
Client.py:
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('192.155.11.79', 9090))
data = client.recv(2048).decode('utf-8')
print('From server side: ', data)
client.close()