美文网首页
golang rpc

golang rpc

作者: 夜空中乄最亮的星 | 来源:发表于2021-10-30 13:56 被阅读0次

    rpc是什么

    RPC(Remote Procedure Call)是远程过程调用,通俗的说就是调用远处的一个函数。

    入门

    一. RPC版 HelloWorld

    服务端代码

    type HelloWorldService struct {
    }
    
    func (hello *HelloWorldService) Hello(request string, reply *string) error {
        *reply = "recieved msg :" + request + "\n"
        return nil
    }
    func Run() {
        rpc.RegisterName("HelloService", new(HelloWorldService))
        listen, err := net.Listen("tcp", "127.0.0.1:9090")
        if err != nil {
            log.Fatalln(err)
        }
        conn, err := listen.Accept()
        if err != nil {
            log.Fatalln(err)
        }
        rpc.ServeConn(conn)
    }
    

    说明:rpc.RegisterName会将HelloWorldService对象中所有满足rpc规则的方法注册为rpc函数,并放在HelloService服务空间之下。其中Hello方法必须满足以下规则:

    1. 访问限制必须公开
    2. 只能有2个序列化参数,第二个参数必须是指针类型
    3. 返回error类型

    客户端代码:

    func main()  {
        client, err := rpc.Dial("tcp", "127.0.0.1:9090")
        if err !=nil {
            log.Fatalln(err)
        }
        var reply string
        err = client.Call("HelloService.Hello", "Hello World", &reply)
        if err !=nil {
            log.Fatalln(err)
        }
        fmt.Println(reply)
    }
    

    首先通过rpc.Dial拨号rpc服务,cient.Call()可理解为呼叫,其第一个参数是rpc的服务服务名和方法名,第二和第三个参数是该方法的2个参数。

    二. 更安全的RPC接口

    在设计RPC的应用中,作为开发人员至少有3中角色:

    1. 服务器端实现RPC方法的开发人员
    2. 客户端调用RPC方法的开发人员
    3. 制定服务端和客户端RPC接口规范的设计人员

    上面HelloWorld的例子虽然看似简单,但是不利于后期的维护和工作的切割,其中存在一个较大的问题是:
    客户端中,Call()方法的参数无法得到编译器安全检查,只有运行时才能发现错误。

    服务端代码:

    • 接口定义
    const HelloServiceName = "study.rpc.HelloService"
    
    type HelloServiceInterface  interface {
        Hello(request string,reply *string) error
    }
    
    func RegisterHelloService(srv HelloServiceInterface) error {
        return rpc.RegisterName(HelloServiceName,srv)
    }
    
    • 服务端代码
    type HelloWorldService struct {
    }
    
    func (hello *HelloWorldService) Hello(request string, reply *string) error {
        *reply = "recieved msg :" + request + "\n"
        return nil
    }
    
    func main()  {
        RegisterHelloService(new(HelloWorldService))
        listen, err := net.Listen("tcp", "127.0.0.1:9090")
        if err != nil {
            log.Fatalln(err)
        }
        for  {
            conn, err := listen.Accept()
            if err != nil {
                log.Fatalln(err)
            }
            go rpc.ServeConn(conn)
        }
    }
    
    • 客户端代码
    
    type HelloServiceClient struct {
        *rpc.Client
    }
    
    //检测HelloServiceClient 是否实现了 HelloServiceInterface 
    var _ HelloServiceInterface = (*HelloServiceClient)(nil)
    
    func (client *HelloServiceClient) Hello(request string, reply *string) error {
        return client.Call(HelloServiceName+".Hello",request,reply)
    }
    
    func DialHelloService(network string,addr string) (*HelloServiceClient,error) {
        client, err := rpc.Dial(network, addr)
        if err !=nil {
            return nil,err
        }
        return &HelloServiceClient{client},nil
    }
    
    func main()  {
        service, err := DialHelloService("tcp", "127.0.0.1:9090")
        if err !=nil {
            log.Fatalln(err)
        }
        var reply string
        err = service.Hello("Hello world", &reply)
        if err !=nil {
            log.Fatalln(err)
        }
        fmt.Println(reply)
    }
    

    相关文章

      网友评论

          本文标题:golang rpc

          本文链接:https://www.haomeiwen.com/subject/falgaltx.html