Reputation: 119
I'm currently trying to get a hang of how sockets work.
I've followed an online tutorial & the python HOWTO
I have a server:
#!/usr/bin/env python3
import socket
HOST = '127.0.0.1' #standard loopback interface address (localhost)
PORT = 9999
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind((HOST, PORT))
serversocket.listen()
(clientsocket, address) = serversocket.accept()
with clientsocket:
print('Connected by', address)
while True:
data = clientsocket.recv(1024)
if not data:
break
clientsocket.sendall(data)
clientsocket.shutdown(socket.SHUT_RDWR)
clientsocket.close()
and a client:
#!/usr/bin/env python3
import socket
HOST = '127.0.0.1' #server hostname or IP address
PORT = 9999
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(b'Hello world!')
data = s.recv(1024)
s.shutdown(socket.SHUT_RDWR)
s.close
print('Received', repr(data))
The server listens for a connection, accepts it and echos whatever it receives.
In the python HOWTO it was emphasized to always close a socket.
Now when I run both scripts in seperate terminals the client does as expected:
Received b'Hello world!'
The terminal with the server gives me the following error:
Connected by ('127.0.0.1, 42780')
Traceback (most recent call last):
File "echo-server.py", line 19, in <module>
clientsocket.shutdown(socket.SHUT_RDWR)
OSError: [Errno 9] Bad file descriptor
From looking around stackeoverflow I learned that
it was because of closing the Python file from "the outside", i.e. not from the file object's close() and I assume this means the socket I am trying to call socket.shutdown()
on has already been shutdown.
Now when I comment line 19 out in the server script
#clientsocket.shutdown(socket.SHUT_RWDR)
everything works as expected without any errors.
The terminals show
Connected by ('127.0.0.1, 42780')
and
Received b'Hello world!'
From my understanding this behaviour is caused by the with statement.
Now to my actual questions:
socket.shutdown()
unnecessary by completing that task itself?socket.close()
still necessary or is that done by the with statement aswell? (Commenting that line out didn't give me any different results)In the end I want to make sure how to close a socket properly from the start since the HOWTO put much emphasis on proper form.
Upvotes: 0
Views: 3892
Reputation: 178125
close
is unnecessary in a with
since it calls close automatically when exiting the with
block, but shutdown
can still be called inside the with
before it exits:
with clientsocket:
print('Connected by', address)
while True:
data = clientsocket.recv(1024)
if not data:
clientsocket.shutdown(socket.SHUT_RDWR)
break
clientsocket.sendall(data)
Upvotes: 1
Reputation: 119
As @Peter Wood pointed out the documentation does contain the answer to my question:
Changed in version 3.2: Support for the context manager protocol was added. Exiting the context manager is equivalent to calling close().
Furthermore:
Sockets are automatically closed when they are garbage-collected, but it is recommended to close() them explicitly, or to use a with statement around them.
Since calling fileObject.close()
on a fileObject that has already been closed does not produce an error commenting that specific line out did not lead to any different results.
The way I interpret that:
It is not intended to explicitly call socket.shutdown()
on a socket within a with
statement.
Calling socket.close()
on a socket in a with
statement is unnecessary.
Upvotes: 1