2012-04-13 86 views
2

我有一個父進程,它創建2個服務器套接字並在它們上調用select()來等待新的連接。當連接到達時,一條消息被髮送到一個子進程(在創建服務器套接字之後,使用fork()創建,因此它們被共享)。爲什麼select()在父進程中使accept()在子進程中不可用?

在這個孩子,在服務器套接字上調用accept()不起作用。我得到了一個EAGAIN錯誤(非阻塞套接字)。而在主流程中調用accept()完美運作。

當然,我根本不會在主流程中調用accept(),我只是測試了一下以檢查它是否工作,並且確實如此。

爲什麼我不能在父母的select()之後的子進程中調用accept()

編輯:這裏的目標是創建一個固定數量的工人(比方說8)來處理客戶端連接,就像在prefork模型中一樣。這些連接將是長連接,不像HTTP。目標是負載均衡工作人員之間的連接。

爲此,我使用一個共享內存變量,它爲工作人員包含當前連接的客戶端的數量。我想「問」具有最少數量的客戶端的工作人員來處理新的連接。

這就是爲什麼我在父級中執行select(),然後將消息發送給子進程,因爲我想「選擇」哪個進程將處理新的連接。

服務器監聽一個以上的插座(一個用於SSL,一個沒有),這就是爲什麼我在孩子過程中使用select()並沒有直接accept(),因爲我可以在我的孩子們的工人多插座不accept()

+2

EAGAIN並不是真正的錯誤,它只是意味着呼叫是非阻塞的,但沒有連接準備就緒。只是睡一會兒,然後再試一次。當然,除EAGAIN之外的任何其他錯誤都是實際的錯誤。 – 2012-04-13 14:07:55

+0

爲什麼不在fork之前先調用'accept'?特別是因爲你知道它的工作原理。 – 2012-04-13 14:18:22

+0

我不明白你在做什麼。您能否請張貼一些簡單的代碼,讓我們重現您的觀察? – moooeeeep 2012-04-13 14:26:47

回答

3

事實上,問題不是我第一次想到的。這裏是我所做的工作流程之間的連接的基本負載平衡的概述。

  • 主處理(父)創建2個服務器套接字,綁定()和聽()它們(使用和不使用SSL例如)
  • 創建8個孩子用叉子(處理),所以它們繼承父的插座
  • 的主要過程在一個無限循環
  • 當它的兩個插口之一是可用的,它通過管道將消息發送到一個孩子跑select()。這個孩子是由共享內存值決定的,其中包含當前的「子進程」中的客戶端數量。選擇當前處理最少數量客戶端的進程。
  • 然後這孩子過程中的服務器套接字上調用accept()(套接字兩人在管傳遞之間使用,所以孩子知道調用accept()哪一個)

的問題是,我的父母進程告訴孩子接受套接字並立即重新進入循環,它再次運行select()。但是如果孩子還沒有接受套接字,select()會再次返回,對於相同的連接。這就是爲什麼我得到一個EAGAIN錯誤,實際上我叫accept()兩次(或更多取決於速度 - 進程間競爭條件)!

解決方案是等待孩子回答管道上的問題,如「嗨,我接受了連接,沒關係!」,然後返回到select()循環。

這工作得很好。在Python中的實現可以在這裏得到好奇:https://github.com/thibautd/Kiwi

相關問題