Reputation: 457
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.
Upvotes: 18
Views: 47160
Reputation: 478
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
Upvotes: 23
Reputation: 2065
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
Upvotes: 1
Reputation:
s_closed result pic s_closed returns true/false as wie lin said,its there (I have used and tested it,can see in picture) . or you can use s.___getstate__
Upvotes: 0
Reputation: 12357
The only way that client.recv
can return an empty string is at end of file (i.e. server side is gone).
It's not possible to send a zero length message via a SOCK_STREAM
connection. If the server wanted to send an empty string, it would need to send some other indicator (for example, a C-style empty string is actually a one-byte string containing only a single zero byte -- the null terminator).
If your server was truly stopped, you should have gotten an empty string. Are you sure you did not? Your loop shown above isn't checking for that condition. If the server is stopped with the code shown, you will simply sit in the loop, receiving a zero byte string, calling processNotificationMessage
with the (empty) string, sleeping for a tenth of a second and then going back to receive another zero byte string, ad infinitum. You need to check for the condition and break
from the loop (if not msg: break
).
Upvotes: 7