如何知道在python中是否关闭套接字连接?

时间:2016-03-08 07:29:48

标签: python sockets

我仍然对了解套接字连接的状态感到困惑。这就是我正在做的事情。

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)

我想连接到服务器并永远保持接收数据。但是,如何知道我的客户端连接是否由于某种原因而关闭?

通过谷歌搜索,我发现 client.recv()将返回一个空字符串或 client.recv()将抛出一个异常(但那里)我停止服务器时也不例外。但是,如果服务器本身有时会发送一个空字符串怎么办?如果我尝试通过检查空字符串重新连接它会抛出一个已经连接的异常。这里的解释(How to tell if a connection is dead in python)对我不起作用。

重新启动服务器时,客户端未收到任何数据。

5 个答案:

答案 0 :(得分:3)

 fileno will return -1 in dead sockets        

   cli, addr = self.sock.accept()
   print(cli.fileno())
   cli.close()
   print(cli.fileno())

输出

376
-1

来自文档18.1 - Socket

  

socket.fileno()返回套接字的文件描述符(一个小整数),   失败时为-1或-1。这对select.select()很有用。

此外,套接字在技术上也是一个列表,您可以在其中找到[关闭]标记

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

答案 1 :(得分:1)

client.recv返回空字符串的唯一方法是在文件末尾(即服务器端不见了)。

无法通过SOCK_STREAM连接发送零长度消息。如果服务器想要发送一个空字符串,则需要发送一些其他指示符(例如,一个C风格的空字符串实际上是一个只包含一个零字节的单字节字符串 - 空终止符)。

如果你的服务器真的停了,你应该得到一个空字符串。你确定没有吗?上面显示的循环不检查该条件。如果使用显示的代码停止服务器,您将只是坐在循环中,接收零字节字符串,使用(空)字符串调用processNotificationMessage,休眠十分之一秒然后返回接收另一个零字节字符串,无限广告。您需要从循环(break)检查条件和if not msg: break

答案 2 :(得分:0)

怎么样: s._closed

这会给出一个真/假的答案。

答案 3 :(得分:0)

s_closed result pic s_closed 返回true / false,因为wie lin说,它在那里(我已经使用并测试了它,可以在图片中看到)。或者您可以使用 s .___ getstate __

答案 4 :(得分:0)

首先,值得一提的是,在大多数情况下,最好在主处理程序循环中处理此问题,您可以在其中简单地测试EOF(socket.recv()收到的空字符串。但是,我遇到了需要对此进行测试以及以下似乎比将另一个回调传递给线程以获得此状态等更好

以下是我正在使用的内容,但我对此非常陌生,所以如果有更好或更有效的方法,请提供反馈,我会更新此答案。

最好的方法是检查getpeername()(测试socket.recv()这里是不好的,因为我们的测试会改变缓冲区,例如。)

  

返回远程端点的地址。对于IP套接字,地址信息是一对(hostaddr,端口)。

如果失败则会引发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

注意:我在那里进行了第一次if-check,因为我正在测试一个可能为None的属性。

  1. 这并不像我想的那样明确,但在我的测试中似乎是准确的。
  2. 原始问题提到想知道没有连接的原因。这没有解决这个问题。
  3. 此外,如果套接字的本地端关闭,另一个答案提到fileno()会返回一个负数。我得到了相同的错误9.无论哪种方式,这都不会测试另一方是否有效。

    >>> 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