一、HTTP RPC
package main
import (
"errors"
"fmt"
"net/http"
"net/rpc"
)
type Args struct {
A, B int
}
type Math int
func (m *Math) Multiply(args *Args, reply *int) error{
*reply = args.A * args.B
return nil
}
//
type Quotient struct {
Quo, Rem int //商、餘數
}
func (m *Math) Divide(args *Args, quo *Quotient) error{
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
func main() {
math := new(Math)
rpc.Register(math) //註冊
rpc.HandleHTTP()
err := http.ListenAndServe(":1234", nil)
if err != nil {
fmt.Println(err.Error())
}
}
package main
import (
"fmt"
"log"
"net/rpc"
"os"
)
//需要注意的是 兩邊均需要定義的類型存在
type Args struct {
A, B int
}
type Quotient struct {
Quo, Rem int
}
//請求調用rpc
func main() {
if len(os.Args) != 2 { //獲取命令行參數 參數個數若不爲2
fmt.Println("Usage: ", os.Args[0], "server")
os.Exit(1) //退出
}
serverAddr := os.Args[1]
//走的是tcp http也是基於tcp的
client, err := rpc.DialHTTP("tcp", serverAddr+":1234")
if err != nil {
log.Fatal("dialing:", err)
}
args := Args{17, 8} //入參
var reply int // 返回值
err = client.Call("Math.Multiply", args,&reply)
if err != nil {
log.Fatal("Math error:", err)
}
fmt.Printf("Math: %d*%d=%d\n",args.A, args.B, reply)
var quo Quotient
err = client.Call("Math.Divide", args, &quo)
if err != nil {
log.Fatal("Math error:", err)
}
fmt.Printf("Math: %d/%d=%d remainder %d\n", args.A, args.B, quo.Quo, quo.Rem)
}
先啓動servergo, 然後再啓動client.go(傳遞參數localhost)發現如下輸出:
下面將http rpc改爲tcp rpc 實際上屬於降級操作,因爲http是基於tcp的
二、TCP RPC
type Args struct {
A, B int
}
type Math int
//提供乘法運算
func (m *Math) Multiply(args *Args, reply *int) error{
*reply = args.A * args.B
return nil
}
//
type Quotient struct {
Quo, Rem int //商、餘數
}
//提供除法運算
func (m *Math) Divide(args *Args, quo *Quotient) error{
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
func main() {
math := new(Math)
rpc.Register(math) //註冊
tcpAddr, err := net.ResolveTCPAddr("tcp",":1234") //tcp網絡 tcp地址
if err != nil {
fmt.Println("Fatal error:", err)
os.Exit(2)
}
listener, err := net.ListenTCP("tcp", tcpAddr) //在指定地址 監聽tcp網絡請求
if err != nil {
fmt.Println("Fatal error:", err)
os.Exit(2)
}
for {
// 發現一個請求 就會產生一個連接對象
conn, err := listener.Accept()
if err != nil {
fmt.Println("conn error")
continue
}
rpc.ServeConn(conn) //只需要把上面建立連接返回的對象 傳進去即可 使用了
//這就是使用Go 標準庫 rpc的好處了
}
}
下面client.go只改一行:
先運行go run server.go
然後運行 go run client.go localhost,如下圖:
三、JSON RPC的實現
server.go文件中只改了下面兩處即可:
然後client.go文件也只是改了兩行代碼: