在 Go 中,RPC 方法的簽名有嚴格的要求,主要是為了保證方法的調用能夠通過網絡正確地傳輸和解析。具體要求如下:
1. 方法必須是導出的
RPC 服務的方法必須是導出的(即首字母大寫)。這是因為 Go 的反射機制要求服務方法可以被外部訪問。
// 錯誤示例:方法首字母小寫,無法被外部訪問
func (s *Server) add(req Req, res *Res) error {res.Num = req.NumOne + req.NumTworeturn nil
}// 正確示例:方法首字母大寫,允許外部調用
func (s *Server) Add(req Req, res *Res) error {res.Num = req.NumOne + req.NumTworeturn nil
}
2. 方法簽名要求
RPC 方法必須滿足以下簽名要求:
-
方法的參數必須是導出的類型(即結構體類型的字段必須是導出的)。Go 的反射機制依賴這些字段。
-
方法的第一個參數是請求參數,必須是值類型或指針類型。通常使用指針類型,因為這樣可以在方法內部修改傳入的參數。
-
方法的第二個參數是響應參數,必須是指針類型。RPC 調用會修改該參數的值,將結果返回給客戶端。
-
方法的返回值只能是一個
error
類型,RPC 系統通過返回的error
類型來判斷調用是否成功。如果返回nil
,表示調用成功;否則,返回錯誤信息。
// 正確示例
func (s *Server) Add(req *Req, res *Res) error {res.Num = req.NumOne + req.NumTworeturn nil // 這里返回nil表示方法執行成功
}// 錯誤示例:返回兩個參數(不符合簽名要求)
func (s *Server) Add(req *Req, res *Res) (int, error) {res.Num = req.NumOne + req.NumTworeturn res.Num, nil // 返回值不符合要求
}
3. 參數和返回值
-
請求參數(
req
):RPC 方法的第一個參數通常是客戶端發送的數據,它必須是一個結構體(或者其他類型),并且是值類型或指針類型。常見做法是使用結構體作為請求參數,且通常使用指針類型來提高效率。 -
響應參數(
res
):第二個參數是用于返回結果的,它必須是一個指針類型,RPC 會通過這個指針修改返回的結果。 -
錯誤返回值:RPC 方法返回的錯誤值是必須的。RPC 系統通過檢查
error
來判斷請求是否成功。如果方法執行成功,error
應該返回nil
;否則,返回錯誤信息。
4. 方法必須是同步的
RPC 方法是同步調用的,客戶端會阻塞直到服務器完成請求并返回結果。RPC 系統會自動管理并發問題,但每個方法調用必須是同步的。如果需要異步行為,通常需要在方法內部使用 goroutine 來處理。
示例:符合要求的 RPC 方法
package mainimport ("fmt""net""net/rpc"
)type Req struct {NumOne intNumTwo int
}type Res struct {Num int
}type Server struct{}// RPC 方法簽名要求:
// - 參數是結構體指針類型
// - 返回值是 error 類型
func (s *Server) Add(req *Req, res *Res) error {res.Num = req.NumOne + req.NumTworeturn nil // 沒有錯誤
}func main() {server := new(Server)// 注冊RPC方法err := rpc.Register(server)if err != nil {fmt.Println("Error registering:", err)return}// 啟動監聽并處理請求listen, err := net.Listen("tcp", ":8080")if err != nil {fmt.Println("Error starting server:", err)return}defer listen.Close()// 啟動 HTTP 服務rpc.HandleHTTP()if err := http.Serve(listen, nil); err != nil {fmt.Println("Error serving:", err)}
}
總結:
-
方法必須是導出的。
-
方法的第一個參數是請求參數,必須是結構體(值類型或指針類型)。
-
方法的第二個參數是響應參數,必須是指針類型。
-
返回值是
error
類型,用于表示調用是否成功。 -
方法調用是同步的,客戶端會等待服務端完成后再返回結果。