2014-11-21 92 views
1

我已經使用SocketServer模塊來創建一個小型服務器。它主要工作,但我有一個關於多個客戶端同時accesing服務器的一些問題:Python socketserver - 與threading.Lock()交互?

  1. 當使用絕對基本的TCP SocketServer的,即沒有ThreadingMixin或ForkingMixin - 當第二個客戶端試圖連接到服務器上發生了什麼在它完成爲第一個客戶提供服務之前;第二個連接會被刪除嗎?或者第二個客戶端會阻止?

  2. 我嘗試添加ThreadingMixin。在這種情況下,我需要保護的服務器代碼的某一代碼塊與鎖

 
lock = threading.Lock() 
with lock: 
    # Do stuff here ... 
    # ... 

# Continue in unlocked scope. 

但鎖好像忽略了 - 整個事情崩潰。而不是與我也嘗試使用lock.aquire()& lock.release() - 那麼它似乎無條件地封鎖lock.aquire()。所以對我來說,似乎ThreadingMixin不會很好地與threading.Lock()一起玩。

編輯:丹關於使用相同的鎖的評論可能是我的鎖定問題的關鍵;我目前的處理程序代碼如下所示:

class MyThreadedHandler(SocketServer.BaseRequestHandler): 

    def handle(self): 
     lock = threading.Lock()  <-- Each thread a separate lock?! 
     with lock: 
      # Do serial stuff 
     # Continue parallell processing. 

所以 - 我想每個線程將鎖定它的個人鎖 - 不是非常多一點!

+1

對於問題#2,您能向我們展示一個我們可以運行的小例子來證明您看到的問題嗎?創建自己的鎖定和鎖定應該沒有問題 - 不應該被忽略,也不應該讓程序崩潰。 (通過崩潰,你的意思是有例外嗎?)除非你正在做一些特殊的需要'acquire()'或'release()'的東西,否則堅持用'lock'。不要忘記鎖定相同的鎖(不是由同一行代碼創建的兩個或多個不同的鎖!) – 2014-11-21 16:35:53

回答

1
  1. 當您在BaseServer上致電serve_forever時,該線程專用於處理服務器的事件。傳入連接和數據在套接字隊列中等待,直到線程有空閒時抓取它們。因此,新的連接和數據將一直等到您的當前處理程序返回。如果你有一個處理程序阻塞,所有傳入的連接和數據將一直等到它完成。

您可以等待的連接數量有一個適度的限制。一旦超過這個限制,TCP協議棧通常會發送一個RESET來告訴另一端消失。您可以通過覆蓋server_activate並調用具有較大值聽更改值:

def server_activate(self): 
    socket.listen(32) 

謙虛不一定是壞事 - 它讓你的服務器不被淹沒。

套接字將會排隊的數據量也有限制,但它對它更加溫和。它只是通知對方,它的接收窗口已滿,請稍後閉嘴。

編輯 2.與鎖的問題....鎖應該與資源(通常是數據,但也許一個I/O端口,甚至寫一個文件關聯,以確保線路別交叉)需要保護,而不是線程正在執行。如果你有多個鎖,你必須小心......死鎖很容易寫!

+0

非常感謝;在這種情況下,我已經用Python自己編寫了這個小而簡單的客戶端。 TCP RESET是否會被操作系統透明地處理,還是我不得不在客戶端手動支持的東西? – user422005 2014-11-21 17:32:39

+0

@ user422005 - 由操作系統自動完成。 – tdelaney 2014-11-21 17:39:16

0

要回答問題#1,當您同步使用服務器(綁定和偵聽)套接字並且沒有線程或分支時,新連接將排隊。他們一直等到服務器開始處理它們。

當在套接字上調用listen()時,參數是這個連接隊列的長度,等待調用accept(),它將逐個返回它們。

如果您的ServerSocket沒有並行處理連接(與線程或進程),則併發連接必須等待。如果有太多的併發連接,看起來它們會被丟棄。