I have some code that is reading data (if there is any) from a non-blocking socket and printing it, but somehow when this happens (data is received & printed) the function then blocks and does not return unless I kill the sending process (which also uses a non-blocking stream to send the data).
Obviously I have done something wrong but for the life of me I can't see it - the socket is non-blocking and I think the continue
statements are somewhat redundant. Python isn't my main language so I'm assuming I've made a daft mistake in this somehow.
This is the socket setup which accepts connections & appends them to the list - I am assuming the non-blocking nature of the socket is retained on accept():
# Open socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setblocking(False) # Make port non-blocking
s.bind((HOST, PORT))
s.listen(MAX_CONN)
#print("Listening on port %d" % PORT)
connection_list = []
connection_list.append(s)
while True:
# Get the list sockets which are ready to be read through select
readable, writable, errored = select.select(connection_list, [], [], 0) # 0 = No timeout / do not block
for sock in readable:
# New connection
if sock == s:
# New connection received through server_socket
sockfd, addr = s.accept()
connection_list.append(sockfd)
print("Client (%s, %s) connected" % addr)
This is the receiver-side Python code that I believe is at fault, it's polled from a main loop:
def handle_replies():
global connection_list
for sock in connection_list:
if sock != s: # Ignore our open listening socket
try:
data = sock.recv(1024)
except socket.error as e:
err = e.args[0]
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
print("Would block") # Socket has no data for us
else:
# a "real" error occurred
print("Error: %s" % e)
continue # To next sock in list
else:
if data:
print("<%s> sent %s" % (str(sock.getpeername()), data))
continue
If I send some data to the socket from another process, I get (for example): <('127.0.0.1', 33196)> sent b'[HELLO:STATUS]'
but then it just stops until I kill the sending process.
This is the [relevant parts of] sending-side code (GTK3 C code) which I think is correct and doesn't block or hang at the send call:
GSocket *sock = g_socket_connection_get_socket(connection);
g_socket_set_blocking( sock, FALSE);
/* use the connection */
GInputStream * istream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
GOutputStream * ostream = g_io_stream_get_output_stream (G_IO_STREAM (connection));
bytes = sprintf(buffer, "[HELLO:STATUS]");
g_output_stream_write (ostream, buffer, (gsize)bytes, NULL, NULL);
So, what have I missed or done wrong in all this?
Well @Max's comment led me straight to it:
for sock in readable:
# New connection
if sock == s:
# New connection received through server_socket
sockfd, addr = s.accept()
sockfd.setblocking(False) # This isn't inherited - set it again!
connection_list.append(sockfd)
print("Client (%s, %s) connected" % addr)
The non-blocking state of the port isn't inherited on accept(), adding sockfd.setblocking(False)
fixed it.