RPC与Protobuf(五)
RPC实现上下文信息
基于上下文可以针对不同的客户端提供定制化的RPC服务,我们可以通过为每个连接提供独立的RPC服务来实现对上下文的特性的支持,下面我们将针对每个RPC服务进行登陆验证,如果通过服务登陆就可以调用RPC,首先是proto目录下的proto文件:
syntax = "proto3"; package proto; message String { string value = 1; }
当然我们需要使用特殊的命令生成相应的接口文件: protoc --go_out=. hello.proto ;紧接着是服务端代码, ctx_service.go:
package main
import (
"fmt"
"log"
"net"
"net/rpc"
"rpc_protobuf/proto"
)
type HelloServiceCtx struct {
conn net.Conn
isLogin bool
}
func (p *HelloServiceCtx) Login(request *proto.String, reply *proto.String) error {
if request.GetValue() != "user:password" {
return fmt.Errorf("auth failed")
}
log.Println("login OK")
p.isLogin = true
return nil
}
func (p *HelloServiceCtx) Hello(request *proto.String, reply *proto.String) error {
if !p.isLogin {
return fmt.Errorf("please login")
}
reply.Value = "hello :"+ reply.GetValue() + ", from " + p.conn.LocalAddr().String()
return nil
}
func main() {
listener, err := net.Listen("tcp",":1234")
if err != nil {
log.Fatal("tcp is error")
}
// 基于每个连接创建一个RPC服务
for {
conn, err:= listener.Accept()
if err != nil {
log.Fatal("accept error")
}
go func() {
defer conn.Close()
p := rpc.NewServer()
p.Register(&HelloServiceCtx{conn:conn})
p.ServeConn(conn)
}()
}
}
然后是客户端代码ctx_client.go:
package main
import (
"fmt"
"log"
"net/rpc"
"rpc_protobuf/proto"
)
func main() {
// 拨号本端1234端口服务
client, err := rpc.Dial("tcp", "localhost:1234")
if err != nil {
log.Fatal("TCP error:", err)
}
// 统一采用接口提供的参数,和请求参数
var reply = &proto.String{}
var param = &proto.String{
Value: "user:password",
}
// 先登陆后在调服务
err = client.Call("HelloServiceCtx.Login", ¶m, &reply)
if err != nil {
log.Fatal(err)
}
// 调用远程服务
err = client.Call("HelloServiceCtx.Hello", ¶m, &reply)
if err != nil {
log.Fatal(err)
}
fmt.Println(reply)
}
到处RPC和Protobuf相关知识就介绍到这了, 如果想深度研究可以访问官网,之后我们可能会介绍gRPC相关知识。

浙公网安备 33010602011771号