2011-12-22 119 views
4

我一直在C中處理一個複雜的服務器 - 客戶機系統,我不確定如何實現套接字通信。任意雙向UNIX套接字通信

簡而言之,系統是一個服務器應用程序,它與數據庫通信並使用UNIX套接字與一個或多個使用fork()創建的子進程進行通信。孩子的目的是運行遊戲服務器。啓動遊戲服務器的過程如下所示:

  1. 服務器/「管理器」標識要創建的數據庫中的遊戲服務器。 (假定數據庫通信已經排序。)
  2. 經理分出一個孩子(「遊戲控制器」)。
  3. 遊戲控制器設置了兩個管道對,然後分叉,用管道替換其子標準輸入,並使用另一個管道輸出標準輸出和標準錯誤。
  4. 遊戲控制器的小孩然後運行execlp()開始運行實際的遊戲服務器可執行文件。

我對套接字的使用經驗很少。在GNU C文檔here中的簡單示例中,我已經在將多個客戶端「複用」之前在服務器應用程序上使用了select()

我現在有一個新的挑戰,因爲系統必須能夠做更多的事情:管理者需要能夠隨意地發送命令給遊戲控制器的孩子(它會通過定期檢查數據庫來發現)並獲得回覆,但期望從它們傳入的任意命令/錯誤併發送回應。

所以,我需要一種「上下文」系統,其中套接字僅在它們之間有意義。換句話說,當一個命令從管理器發送到遊戲控制器時,每一方都需要知道誰在問,並知道答覆是什麼(因此,它是哪個命令的答覆)。

由於select()僅用於瞭解何時有傳入數據,並且線程應該阻塞它,我是否需要另一個線程來發送數據並獲取答覆?這是否需要每個遊戲控制器(儘管在技術上都是「客戶端」)使用偵聽套接字並使用select()

我希望我已經簡明地解釋了系統和問題;如果需要,我會添加更多細節。謝謝!

+0

我想我大部分都能理解,但是你能解釋一下你的意思嗎?「套接字只在他們自己之間有意義」? – frankc 2011-12-22 21:54:22

+0

通過套接字發送的命令將從其對應方回覆,比如如何接受(),並且您收到另一個向另一方向流動的套接字?或者,也許有一種更有效的方式來實現基本的推斷過程。 – Doddy 2011-12-22 22:13:58

+0

「每個參與方都不知道誰在問」,因爲他們知道他們從哪個套接字接收數據? – 2011-12-23 03:19:46

回答

1

好的,我仍然不確定自己是否明白自己的問題所在,所以我只想談談編寫客戶端/服務器應用程序的一些問題。如果我走錯了路,請告訴我。

  1. 服務器將知道哪些客戶端對應哪個客戶端將告訴服務器的方式。基本上,你需要有一個登錄協議。當遊戲控制器連接到服務器時,它會發送一條消息,指出「嗨,我正在註冊爲主機xyz上的控制器foo1,端口abc ...」以及服務器需要了解其客戶端的其他信息。服務器將保留一個將套接字映射到客戶端元數據,狀態等的數據結構。每當它收到新消息時,它都可以輕鬆地將傳入主機/端口映射到其元數據。或者您的協議可能要求在每個傳入消息中,意願客戶端將其註冊的名稱作爲字段發送。

  2. 處理請求/響應可以通過幾種方式完成。首先讓我們在服務器端處理它的網絡部分。正如您所提到的,一種管理方法是使用select(或poll或epoll)來複用套接字。實際上,這通常被認爲是更復雜的做事方式。另一種方法是爲每個傳入的客戶端生成一個線程(或者fork一個進程,這些在目前不太常見)。每個產生的線程都可以讀取它自己分配的套接字,一次響應一條消息,而不必擔心除了正在處理的其他客戶端之外還有其他客戶端。如果有很多客戶端,這個簡單的一對一線程到套接字模型就會崩潰,但如果情況並非如此,那麼值得考慮。

第2部分確實只涵蓋了向服務器發送消息的客戶端和服務器的回覆。當服務器想要啓動通信時會發生什麼?它是如何做到的以及客戶如何處理它?另外,您如何在應用程序級別對通信進行建模,這意味着假設讀/寫部分已關閉,我們如何知道要發送的內容?你可能想要用狀態機來模擬事物。還有很多事情要處理,比如當客戶端崩潰時會發生什麼?什麼時候服務器崩潰?另外,如果你真的有心使用select,也許是因爲你期望很多客戶?明天我會試着增加更多答案。