2017-05-07 82 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模式。