2017-05-07 77 views
0

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

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

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

有没有办法做到这一点?

这类似于https://stackoverflow.com/a/10090348/3084431,但是这些解决方案不会工作,为我的代码:

  1. 这一点是不正确的,封闭不会提高在接受一个例外。关闭,但在线程关闭时不能再被调用。
  2. 我无法连接到此套接字了。插座关闭。
  3. 带有accept调用的线程已经在运行,我无法更改它们。
  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 

我需要的是什么这个代码后已经完成,可以以某种方式阻止受体线,我可以运行。

+0

股票套接字行为有什么问题?如果“接受”是“已经运行”,则在技术上接受一个连接 - 在您停止接受新的连接之前 - 因此一切都可以。如果你想踢所有现有的客户,那就是你应该做的。 –

+1

你将永远无法完成这项工作。你的代码已经有一个严重的竞争条件 - 如果'sock.close()'与'accept'的调用同时执行会发生什么? Python的套接字对象不是线程安全的 - 当另一个线程访问它时,它的状态不能在一个线程中修改。绝对不可能确保'accept'正在运行,而不是即将运行或准备好阻止。所以这*不能*安全地完成,期间。 –

+0

@ivan_pozdeev没有客户端,它只是一个阻塞的'accept'函数,它永远在等待并阻止线程完成。 @DavidSchwartz'sock.close'实际上是在'sock.accept'运行时执行的。问题是套接字现在已关闭,但'sock.accept'仍在运行 – Troido

回答

1

内核没有通知每个侦听器套接字关闭的机制。你必须自己写点东西。一个简单的解决办法是在插座使用的超时:

sock.settimeout(1) 

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

现在,当你关闭套接字下次调用(超时后),以.accept()将抛出一个“坏描述符”异常。

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

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

因此,更改产生这些线程或关闭套接字的代码不是一个选项。

如果是这样,那么你注定要失败。不改变在线程中运行的代码是不可能实现的。这就像问“如何在不修改汽车的情况下修理我的破车”。不会发生,交配。

+0

如果套接字未关闭,则可以修复它。如果它没有关闭,'sock.shutdown'可能会使'accept'函数错误,从而停止线程。尽管如此,插座关闭时很可能不会这样做。我只是希望有人会碰巧知道这样做的一个伎俩。 – Troido

0

您只能在给出selectors的“可读”结果的套接字上调用.accept()。然后,接受需要被中断。

但是如果发生虚假唤醒,无论如何您都应该有监听套接字O_NONBLOCK模式。