【问题标题】:kill socket.accept() call on closed unix socket在关闭的 unix 套接字上杀死 socket.accept() 调用
【发布时间】:2017-10-05 16:55:30
【问题描述】:

Socket.close() 不会停止任何已经在该套接字上运行的阻塞 socket.accept() 调用。

我的 python 程序中有几个线程,它们只在已经关闭的 unix 域套接字上运行阻塞 socket.accept() 调用。 我想通过使 socket.accept() 调用停止或终止这些线程 引发异常。

我试图通过在程序中加载新代码而不停止程序来做到这一点。 因此,更改生成这些线程或关闭套接字的代码不是一种选择。

有什么办法吗?

这类似于https://stackoverflow.com/a/10090348/3084431,但这些解决方案不适用于我的代码:

  1. 这点不正确,关闭不会在接受时引发异常。 shutdown 可以,但是当线程关闭时就不能再调用了。
  2. 我无法再连接到此套接字。套接字已关闭。
  3. 带有接受调用的线程已经在运行,我无法更改它们。
  4. 同3

为了澄清,我写了一些有这个问题的示例代码。 此代码适用于 python 2 和 python 3。

import socket
import threading
import time

address = "./socket.sock"

sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(address)
sock.listen(5)

def accept():
    print(sock.accept())

t = threading.Thread(target=accept, name="acceptorthread")
t.start()

sock.close()

time.sleep(0.5) # give the thread some time to register the closing

print(threading.enumerate()) # the acceptorthread will still be running

我需要的是在这段代码完成后可以运行的东西,它可以以某种方式停止接受者线程。

【问题讨论】:

  • 普通套接字行为有什么问题?如果accept“已经在运行”,则在技术上接受了一个连接您停止接受新连接之前 - 所以一切正常。如果你想踢掉所有现有的客户,那就是你应该做的。
  • 你永远无法完成这项工作。你的代码已经有一个严重的竞争条件——如果sock.close()accept的调用同时执行会发生什么? Python 的套接字对象不是线程安全的——当另一个线程访问它时,它不能在一个线程中修改其状态。绝对无法确保accept 正在运行,而不是即将运行或准备阻止。所以这不能安全地完成,期间。
  • @ivan_pozdeev 没有客户端,它只是一个阻塞的accept 函数,它永远等待并阻止线程完成。 @DavidSchwartz sock.close 实际上是在 sock.accept 运行时执行的。问题是套接字现在已关闭,但 sock.accept 仍在运行

标签: python multithreading sockets unix-socket


【解决方案1】:

内核中没有机制来通知每个侦听器套接字已关闭。你必须自己写一些东西。一个简单的解决方案是在套接字上使用超时:

sock.settimeout(1)

def accept():
    while True:
        try:
            print(sock.accept())
        except socket.timeout:
            continue
        break

现在,当您关闭套接字时,对.accept() 的下一次调用(超时后)将引发“错误描述符”异常。

还要记住 Python 中的套接字 API 不是线程安全的。建议在多线程环境中使用锁(或其他同步方法)包装每个套接字调用。

更高级(和高效)的方法是使用select call 包裹您的套接字。请注意,套接字不必处于非阻塞模式才能使用它。

因此,不能更改生成这些线程或关闭套接字的代码。

如果是这样,那你就完蛋了。不改变线程中运行的代码是不可能实现的。这就像在问“我怎样才能在不修改汽车的情况下修理我的破车”。不会发生的,伙计。

【讨论】:

  • 如果不关闭套接字,则可以修复。如果它没有关闭,sock.shutdown 可能会导致accept 函数错误,从而停止线程。尽管如此,当套接字关闭时,最有可能做这样的事情是不可能的。我只是希望有人会碰巧知道这样做的技巧。
【解决方案2】:

您应该只在某个套接字上调用.accept(),该套接字已从某些selectors 给出“可读”结果。那么,accept 就不需要被打断了。

但在虚假唤醒的情况下,无论如何你都应该让监听套接字处于O_NONBLOCK 模式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    • 2010-09-26
    • 1970-01-01
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多