I'm still confused about knowing the status of my socket connection. This is what I'm doing.
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",9979))
while True:
msg = client.recv(4096)
processNotificationMessage(msg)
time.sleep(0.1)
I want to connect to a server and keep receiving data forever. But how can I know if my client connection was closed due to some reason?
By googling a lot all I found was that the client.recv() will return an empty string or client.recv() will throw an exception (but there was no exception when I stopped my server). But what if the server itself is sending an empty string sometimes? If I try to reconnect by checking for an empty string it throws an exception saying already connected. The explaination here (How to tell if a connection is dead in python) did not work for me.
No data was received by client when I restarted my server.
fileno()
will return -1 for closed sockets.
cli, addr = self.sock.accept()
print(cli.fileno())
cli.close()
print(cli.fileno())
OUTPUT
376
-1
From the docs 18.1 - Socket
socket.fileno() Return the socket’s file descriptor (a small integer), or -1 on failure. This is useful with select.select().
Also the socket is technically a list, with this you can find the [closed] tag
cli, addr = self.sock.accept()
for i in str(cli).split():
print(i)
<socket.socket fd=488, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('10.1.1.2', 80), raddr=('10.1.1.2', 16709)> 488 -1
cli.close()
for i in str(cli).split():
print(i)
<socket.socket fd=504, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('10.1.1.2', 80), raddr=('10.1.1.2', 16833)> 504 <socket.socket [closed] <--- fd=-1, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0> -1
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With