本文以一個 Sudoku Solver 為例,回顧了並髮網絡服務程式的多種設計方案,並介紹了使用 muduo 網路程式庫編寫多線程伺服器的兩種最常用手法。以往的例子展現了 Muduo 在編寫單線程並髮網絡服務程 序方面的能力與便捷性,今天我們看一看它在多線程方面的表現。
本文代碼見: http://code.google.com/p/muduo/source/browse/trunk/examples/sudoku/
下載: http://muduo.googlecode.com/files/muduo-0.2.5-alpha.tar.gz
Sudoku Solver
假設 有這麼一個網路編程任務:寫一個求解數獨的程式 (Sudoku Solver),並把它做成一個網路服務。
Sudoku Solver 是我喜愛的網路編程例子,它曾經出現在《分布式系統部署、監控與進程管理 的幾重境界》、《Muduo 設計與實現之一:Buffer 類的設計》、《〈多線程伺服器的適用場合〉例釋 與答疑》等文中,它也可以看成是 echo 服務的一個變種(《談一談網路編程學習經驗》把 echo 列為 三大 TCP 網路編程案例之一)。
寫這麼一個程式在網路編程方面的難度不高,跟寫 echo 服務 差不多(從網路連接讀入一個 Sudoku 題目,算出答案,再發回給客戶),挑戰在於怎樣做才能發揮現 在多核硬體的能力?在談這個問題之前,讓我們先寫一個基本的單線程版。
協議
一個 簡單的以 /r/n 分隔的文本行協議,使用 TCP 長串連,用戶端在不需要服務時主動中斷連線。
請求:[id:]〈81digits〉/r/n
響應:[id:]〈81digits〉/r/n 或者 [id:] NoSolution/r/n
其中[id:]表示可選的 id,用於區分先後的請求,以支援 Parallel Pipelining,響應中會回應要求中的 id。Parallel Pipelining 的意義見賴勇浩的《以小見大——那 些基於 protobuf 的五花八門的 RPC(2) 》,或者見我寫的《分布式系統的工程化開發方法》第 54 頁關於 out-of-order RPC 的介紹。
〈81digits〉是 Sudoku 的棋盤,9x9 個數字,未知數字 以 0 表示。
如果 Sudoku 有解,那麼響應是填滿數位棋盤;如果無解,則返回 NoSolution 。
例子1:
請求: 000000010400000000020000000000050407008000300001090000300400200050100000000806000/r/n
< p>響應: 693784512487512936125963874932651487568247391741398625319475268856129743274836159/r/n
< p>例子2:
請求: a:000000010400000000020000000000050407008000300001090000300400200050100000000806000/r/n
響應: a:693784512487512936125963874932651487568247391741398625319475268856129743274836159/r/n
例子3:
請求: b:000000010400000000020000000000050407008000300001090000300400200050100000000806005/r/n
響應:b:NoSolution/r/n
基於這個文本協議,我們可以用 telnet 類比用戶端來測試 sudoku solver,不需要單獨編寫 sudoku client。SudokuSolver 的預設連接埠號碼是 9981,因為它有 9x9=81 個格子。