前面玩过grpc, 要安装grpc库,要安装protobuf库等,好多库啊 。通信协议是tcp, 采用protobuf序列化。
下面来看看go原生的rpc(不需要安装一些杂七杂八的库): 1. 基于tcp/gob. 2. 基于http/gob. 3. tcp/jsonrpc. 其中,1和2采用了gob序列化, 有局限性,而 3采用的是json序列化,比较通用。
1. 基于tcp/gob
server.go:
package main
import (
"net"
"log"
"net/rpc"
)
type Params struct {
Width, Height int;
}
type Rect struct{}
// 1. 方法名Area必须大写
// 2. 必须有两个参数,且参数必须是外部能访问的类型或内置类型,且第二个参数必须是指针类型
// 3. 返回值必须是error类型
func (r *Rect) Area(p Params, ret *int) error {
*ret = p.Width * p.Height
return nil
}
func main() {
rect := new(Rect)
rpc.Register(rect) // 注册
tcplisten, err := net.Listen("tcp", "0.0.0.0:8888")
if err != nil {
log.Fatal(err)
}
for {
conn, err := tcplisten.Accept()
if err != nil {
continue
}
go rpc.ServeConn(conn)
}
}
跑起来。
client.go:
package main
import (
"net/rpc"
"fmt"
"log"
"time"
)
type Params struct {
Width int
Height int
}
func main() {
rpc, err := rpc.Dial("tcp", "127.0.0.1:8888")
if err != nil {
log.Fatal(err)
}
for {
ret := 0
err = rpc.Call("Rect.Area", Params{50, 100}, &ret)
if err != nil {
log.Fatal(err)
}
fmt.Println(ret)
time.Sleep(time.Second)
}
}
跑起来。客户端结果为:
5000
5000
5000
5000
5000
如果用tcpdump抓包, 则看不出gob的内容是什么意思。
2. 基于http/gob:
server.go:
package main
import (
"net/http"
"log"
"net/rpc"
)
type Params struct {
Width, Height int;
}
type Rect struct{}
// 1. 方法名Area必须大写
// 2. 必须有两个参数,且参数必须是外部能访问的类型或内置类型,且第二个参数必须是指针类型
// 3. 返回值必须是error类型
func (r *Rect) Area(p Params, ret *int) error {
*ret = p.Width * p.Height
return nil
}
func main() {
rect := new(Rect)
rpc.Register(rect) // 注册
rpc.HandleHTTP();
err := http.ListenAndServe(":8080", nil);
if err != nil {
log.Fatal(err);
}
}
跑起来。
client.go:
package main
import (
"net/rpc"
"fmt"
"log"
"time"
)
type Params struct {
Width int
Height int
}
func main() {
rpc, err := rpc.DialHTTP("tcp", "127.0.0.1:8080");
if err != nil {
log.Fatal(err);
}
for {
ret := 0
err = rpc.Call("Rect.Area", Params{50, 100}, &ret)
if err != nil {
log.Fatal(err)
}
fmt.Println(ret)
time.Sleep(time.Second)
}
}
客户端也跑起来,结果:
5000
5000
5000
5000
5000
5000
5000
5000
5000
如果用tcpdump抓包, 则看不出gob的内容是什么意思。
3. tcp/jsonrpc
server.go:
package main
import (
"net"
"log"
"net/rpc"
"net/rpc/jsonrpc"
)
type Params struct {
Width, Height int;
}
type Rect struct{}
// 1. 方法名Area必须大写
// 2. 必须有两个参数,且参数必须是外部能访问的类型或内置类型,且第二个参数必须是指针类型
// 3. 返回值必须是error类型
func (r *Rect) Area(p Params, ret *int) error {
*ret = p.Width * p.Height
return nil
}
func main() {
rect := new(Rect)
rpc.Register(rect) // 注册
tcplisten, err := net.Listen("tcp", "0.0.0.0:8888")
if err != nil {
log.Fatal(err)
}
for {
conn, err := tcplisten.Accept()
if err != nil {
continue
}
go jsonrpc.ServeConn(conn)
}
}
跑起来。
client.go:
package main
import (
"net/rpc/jsonrpc"
"fmt"
"log"
"time"
)
type Params struct {
Width int
Height int
}
func main() {
rpc, err := jsonrpc.Dial("tcp", "127.0.0.1:8888");
if err != nil {
log.Fatal(err);
}
for {
ret := 0
err = rpc.Call("Rect.Area", Params{50, 100}, &ret)
if err != nil {
log.Fatal(err)
}
fmt.Println(ret)
time.Sleep(time.Second)
}
}
跑起来,客户端结果为:
5000
5000
5000
5000
5000
5000
5000
用tcpdump抓包看看:
11:21:57.620895 IP 127.0.0.1.58698 > 127.0.0.1.8888: Flags [P.], seq 207:276, ack 115, win 12135, options [nop,nop,TS val 534958593 ecr 534957588], length 69
0x0000: 0200 0000 4500 0079 0000 4000 4006 0000 ....E..y..@.@...
0x0010: 7f00 0001 7f00 0001 e54a 22b8 54cc e11f .........J".T...
0x0020: 573c c601 8018 2f67 fe6d 0000 0101 080a W<..../g.m......
0x0030: 1fe2 d201 1fe2 ce14 7b22 6d65 7468 6f64 ........{"method
0x0040: 223a 2252 6563 742e 4172 6561 222c 2270 ":"Rect.Area","p
0x0050: 6172 616d 7322 3a5b 7b22 5769 6474 6822 arams":[{"Width"
0x0060: 3a35 302c 2248 6569 6768 7422 3a31 3030 :50,"Height":100
0x0070: 7d5d 2c22 6964 223a 3532 387d 0a }],"id":528}.
11:21:57.620928 IP 127.0.0.1.8888 > 127.0.0.1.58698: Flags [.], ack 276, win 11622, options [nop,nop,TS val 534958593 ecr 534958593], length 0
0x0000: 0200 0000 4500 0034 0000 4000 4006 0000 ....E..4..@.@...
0x0010: 7f00 0001 7f00 0001 22b8 e54a 573c c601 ........"..JW<..
0x0020: 54cc e164 8010 2d66 fe28 0000 0101 080a T..d..-f.(......
0x0030: 1fe2 d201 1fe2 d201 ........
11:21:57.620935 IP 127.0.0.1.8888 > 127.0.0.1.58698: Flags [.], ack 276, win 11622, options [nop,nop,TS val 534958593 ecr 534958593], length 0
0x0000: 0200 0000 4500 0034 0000 4000 4006 0000 ....E..4..@.@...
0x0010: 7f00 0001 7f00 0001 22b8 e54a 573c c601 ........"..JW<..
0x0020: 54cc e164 8010 2d66 fe28 0000 0101 080a T..d..-f.(......
0x0030: 1fe2 d201 1fe2 d201 ........
11:21:57.621160 IP 127.0.0.1.8888 > 127.0.0.1.58698: Flags [P.], seq 115:153, ack 276, win 11622, options [nop,nop,TS val 534958593 ecr 534958593], length 38
0x0000: 0200 0000 4500 005a 0000 4000 4006 0000 ....E..Z..@.@...
0x0010: 7f00 0001 7f00 0001 22b8 e54a 573c c601 ........"..JW<..
0x0020: 54cc e164 8018 2d66 fe4e 0000 0101 080a T..d..-f.N......
0x0030: 1fe2 d201 1fe2 d201 7b22 6964 223a 3532 ........{"id":52
0x0040: 382c 2272 6573 756c 7422 3a35 3030 302c 8,"result":5000,
0x0050: 2265 7272 6f72 223a 6e75 6c6c 7d0a "error":null}.
果然, 使用的是json编码, 有点意思。
就这样, 不多说。