First, it is worth saying that in most situations it seems best to handle this in the main handler loop where you can simply test for EOF (empty string received by socket.recv()
. However, I came across the need to test for this and the following seemed better than passing another callback in to the thread to get this state, etc)
The following is what I am using, but I am very new to this though, so please provide feedback if there is a better or more efficient way to do this and I'll update this answer.
It seems like the best way to do this is to check getpeername()
(testing socket.recv()
here is bad since our test would alter the buffer, for example.)
Return the address of the remote endpoint. For IP sockets, the address info is a pair (hostaddr, port).
If this fails it raises a socket.error [Errno 9] Bad file descriptor.
def is_socket_valid(socket_instance):
""" Return True if this socket is connected. """
if not socket_instance:
return False
try:
socket_instance.getsockname()
except socket.error as err:
err_type = err.args[0]
if err_type == errno.EBADF: # 9: Bad file descriptor
return False
try:
socket_instance.getpeername()
except socket.error as err:
err_type = err.args[0]
if err_type in [errno.EBADF, errno.ENOTCONN]: # 9: Bad file descriptor.
return False # 107: Transport endpoint is not connected
return True
Note: I have the first if-check in there because I am testing an attribute that may be None as well.
- This isn't as explicit as I'd like but in my tests it seems to be accurate.
- The original question mentions wanting to know the reason for not being connected. This doesn't address that.
Additionally, another answer mentions fileno()
returns a negative number if the local side of the socket is closed. I get the same error 9. Either way, this doesn't test the other side in the case that this is valid.
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.fileno()
10
>>> s.close()
>>> s.fileno()
---------------------------------------------------------------------------
error Traceback (most recent call last)
----> 1 s.fileno()
/tools/package/python/2.7.13/lib/python2.7/socket.pyc in meth(name, self, *args)
226
227 def meth(name,self,*args):
--> 228 return getattr(self._sock,name)(*args)
229
230 for _m in _socketmethods:
/tools/package/python/2.7.13/lib/python2.7/socket.pyc in _dummy(*args)
172 __slots__ = []
173 def _dummy(*args):
--> 174 raise error(EBADF, 'Bad file descriptor')
175 # All _delegate_methods must also be initialized here.
176 send = recv = recv_into = sendto = recvfrom = recvfrom_into = _dummy
error: [Errno 9] Bad file descriptor