2013-05-25 174 views
0

使用管道我想用C,而我的朋友編程客戶端一個小組聊天系統的服務器端程序。對於服務器接收的每個客戶端連接,它會分派子進程以處理客戶端並繼續接受任何可能的更多客戶端。與多個客戶端

服務器需要發送所有在線用戶(連接的客戶端)的列表,每個當前連接的客戶機,爲此我已經使用管道。基本上,當創建子進程時,它通過套接字接收來自客戶端的信息,並通過管道將這些信息發送給父節點,父節點保存所有客戶端的列表。每當客戶做出改變,如開始聊天或斷開連接時,該列表必須更新。例如,如果客戶端斷開連接,則子節點通過管道將消息發送給父節點,並且父節點對列表進行必要的操作以使其得到更新。請注意,管道是爲每個新連接創建的。

我的問題是,例如,如果我收到接連3連接一個和第二個孩子斷開,父不讀書從管道的信息,因爲這樣的父母已經從第二個孩子不同的管道。 (請記住,由於已建立第三個連接,因此已創建新管道)。我該如何解決這個問題?

我也嘗試過創建一個通用管道,但是如果在讀/寫之前我沒有關閉管道,那麼我得到一個錯誤,如果我關閉它們,當第二個客戶端連接時會出現分段錯誤,關閉。

任何幫助將不勝感激,因爲我一直在尋找了幾個小時也沒有用。

謝謝。當創建一個孩子,因爲它創建子

+1

我建議尋找像'epoll'這樣的東西,以便您可以更輕鬆地在單個進程中保持所有併發連接的規模。然後,您不需要通過管道進行交談,並可以以異步方式直接與套接字進行通話。 –

+0

事實上,你應該使用套接字和異步IO而不是管道。 (您可能希望在您的實現中構建此庫:https://developer.gnome.org/glib) – moooeeeep

+0

我仍然能夠在所有客戶端之間保留一個通用列表嗎? – gracey

回答

0

父服務器進程知道。它可以通過設置SIGCLD信號處理程序來告訴孩子何時死亡,以便在孩子死亡時通知它。孩子有N-1條管道關閉 - 那些去其他孩子(除非有些孩子已經死亡)。父進程關閉它創建的管道的寫入結束;子進程關閉它所繼承的管道的讀取端(這留下了一個到客戶端的套接字以及爲它與父進行通信而創建的管道的寫入結束)。

如果您需要知道孩子何時開始與客戶進行交流,那麼您需要沿管道從孩子向父母發送消息。如何判斷孩子何時停止交流並不那麼明顯 - 在你宣佈孩子再次空閒之前需要等待多久?

在父項中,您最終會在偵聽套接字和所有讀取管道上以某種形狀或形式輪詢(select(),poll(),epoll())。當某些活動發生時,父母會醒來並做出適當的迴應。只要不需要擴展到成千上萬的客戶,這是一個可行的設計。它需要小心,特別是在關閉足夠多的文件描述符時。

你說:

我的問題是,例如,如果我收到3只連接了一個又一個,第二個孩子斷開,父不讀書從管道的信息,因爲這樣的家長有不同的從第二個孩子的管道。 (請記住,由於已建立第三個連接,因此已創建新管道)。我該如何解決這個問題?

父應該有一個打開的文件描述符(打開管道以讀取各種子對象)的數組,以及指示哪個子對象(PID)位於管道的另一端。父母會在管道上收到EOF時,或者通知孩子已經死亡(通過waitpid()或親屬)時關閉管道。輪詢機制會告訴你什麼時候管道關閉,至少是間接的(你會被告知文件描述符不會被阻塞,然後你得到EOF--零字節被讀取)。

在你的場景中,父節點打開一個監聽套接字,再加上3個讀取管道到3個孩子的文件描述符(加上標準輸入,輸出和錯誤,也許syslog)。

儘管您可以使用所有孩子的單個管道,但處理起來要棘手得多。您必須確定哪個孩子在消息中寫下了每條消息,確保消息是由孩子自動寫入的。家長必須能夠說出在任何時候閱讀的內容,以免混淆。單個管道的優點是對輪詢系統調用的操作較少;它也會無限制地擴展(不會耗盡文件描述符)。

在這兩種情況下都不應該遇到核心轉儲問題。