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?
Advertisement
Answer
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.