运用go标准库写一个rpc例子
服务端
package mainimport ("fmt""net""net/rpc"
)//对象
type Hello struct {
}
//对象方法
func (h *Hello) HelloWorld(name string, resp *string) error {*resp = name + "你好"return nil
}func main() {//1. 注册RPC服务,绑定对象方法;这里采用的是默认的rpc对象err := rpc.RegisterName("hello", new(Hello))if err != nil {fmt.Println("rpc RegisterName error")return}//2. 初始化监听器listener, err := net.Listen("tcp", "127.0.0.1:8800")if err != nil {fmt.Println("net Listen error")return}defer listener.Close()//3.建立连接conn, err := listener.Accept()if err != nil {fmt.Println("listener Accept error")return}defer conn.Close()//4.将连接绑定rpc服务rpc.ServeConn(conn)
}
注意绑定的对象方法,必须有两个参数,第二个参数必须是“指针类型”为传出参数。方法只有一个error类型的返回值。
客户端
package mainimport ("fmt""net/rpc"
)func main() {//建立连接conn, err := rpc.Dial("tcp", "127.0.0.1:8800")if err != nil {fmt.Println("rpc Dial error")return}defer conn.Close()//调用远程函数var resp stringerr = conn.Call("hello.HelloWorld", "李白", &resp)if err != nil {fmt.Println("conn Call error")return}fmt.Println(resp)
}
注意:上面代码中rpc的远程函数调用采用的是golang中特有的序列化包gob,其他语音不能解析。所以,要进行不同语言之间的rpc通信可以采用通用的序列化方式,如json,protobuf
然后,在实际运用中都会对服务端和客户端的再进行封装:
protobuf添加rpc服务
此时使用的protobuf编译指令,将定义好的proto规则和rpc服务生成go代码,需要用到的是grpc
protoc --go_out=. *.proto
protoc --go-grpc_out=. *.proto
举例:
定义proto文件,然后用上面两个命令生成go代码
syntax="proto3";package pb;//option go_package = "path;name"; path 表示生成的go文件的存放地址,会自动生成目录的
// name 表示生成的go文件所属的包名
option go_package=".;pb";message HelloRequest {string requestName = 1;
}message HelloResponse {string responseMsg = 1;
}service Hello{rpc SayHello(HelloRequest) returns (HelloResponse);
}
服务端:
package mainimport ("context""fmt""google.golang.org/grpc""net""rpc_day01/pb"
)type My struct {pb.UnimplementedHelloServer //必须嵌套这个
}func (m *My) SayHello(c context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {var resp pb.HelloResponseresp.ResponseMsg = req.RequestName + " hello !!"return &resp, nil
}func main() {//1 初始化一个gpc对象grpcServer := grpc.NewServer()//2 注册服务pb.RegisterHelloServer(grpcServer, &My{})//3 设置监听,指定IPlistener, err := net.Listen("tcp", "127.0.0.1:8801")if err != nil {fmt.Println("net Listen error")return}defer listener.Close()//4 启动服务grpcServer.Serve(listener)
}
客户端:
package mainimport ("context""fmt""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""log""rpc_day01/pb"
)func main() {//连接grpc服务(无加密)conn, err := grpc.Dial("127.0.0.1:8801", grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatal(err)}defer conn.Close()//初始化grpc客户端grpcClient := pb.NewHelloClient(conn)resp, err := grpcClient.SayHello(context.Background(), &pb.HelloRequest{RequestName: "李白"})if err != nil {log.Fatal(err)}fmt.Println(resp.ResponseMsg)
}