Description
Bug report
Updated: In Linux (Python 3.8.10, Ubuntu 20.04.4 LTS), it works as expected.
Maybe the difference is that in Windows recv() can return with an error (WSAESHUTDOWN) for shutdown sockets whereas in Linux recv() returns with a byte count of zero.
Original post:
In my experience, a blocked call to a connected socket's recv() should be released by issuing a socket.shutdown(socket.SHUT_RDWR) - or socket.shutdown(socket.SHUT_RD)
That's according to function in Linux as well as TCP/IP standard (not sure here).
In Python, the shutdown() call seems to be ignored all together. See example, below.
Your environment
- CPython versions tested on: 3.9.12
- Operating system and architecture: Windows 10 Pro
Example
import threading
import socket
import time
HOST = "127.0.0.1"
PORT = 1234
def serverThread():
print(f"Server starting for {HOST}:{PORT}")
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print(f"Connected by {addr}")
print("Server won't send anything")
#conn.sendall(b"Hello")
time.sleep(10)
print("Server terminating...")
conn.shutdown(socket.SHUT_RDWR) # Tell the client we're shutting down the connection - not absolutely necessary
conn.close()
s.close()
server = threading.Thread(target=serverThread, name="SERVER")
clientSocket = None
def clientThread():
print(f"Connecting to server {HOST}:{PORT}")
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
global clientSocket
clientSocket = s
s.connect((HOST, PORT))
print("Client is receiving...")
try:
data = s.recv(64)
except OSError as e:
print(f"Exception in client: {e}")
else:
print(f"Client has received: {data!r}")
print("Client terminating...")
if s.fileno() < 0:
print("Someone has already closed the socket. Who is messing with my socket?!?!?")
else:
s.shutdown(socket.SHUT_RDWR) # Tell the server we're shutting down the connection - not absolutely necessary
s.close()
print("Client is done")
client = threading.Thread(target=clientThread, name="CLIENT")
print("Server and Client is set up")
server.start()
client.start()
time.sleep(2)
if clientSocket.fileno() < 0:
print("Client socket is already closed, we're done")
exit()
print("\nShutting down socket")
clientSocket.shutdown(socket.SHUT_RDWR)
print("\n *** Nothing changed, right? ***")
time.sleep(2)
print("\n\nShutting down socket using close() coming up...")
time.sleep(2)
print("Now!")
clientSocket.close()
print("\n >>> Now, we succeeded with releasing the blocked recv() call in client\n\n")