当前位置 博文首页 > go语言net包rpc远程调用的使用示例

    go语言net包rpc远程调用的使用示例

    作者:怀素真 时间:2021-06-15 18:26

    rpc 包提供了一个方法来通过网络或者其他的I/O连接进入对象的外部方法. 一个server注册一个对象, 标记它成为可见对象类型名字的服务。注册后,对象的外部方法就可以远程调用了。一个server可以注册多个 不同类型的对象,但是却不可以注册多个相同类型的对象。

    只有满足这些标准的方法才会被远程调用视为可见;其他的方法都会被忽略:

    - 方法是外部可见的。
    - 方法有两个参数,参数的类型都是外部可见的。
    - 方法的第二个参数是一个指针。
    - 方法有返回类型错误

    一、基于http的RPC

    服务端:

    package main;
    
     
    
    import (
    
      "net/rpc"
    
      "net/http"
    
      "log"
    
    )
    
     
    
    //go对RPC的支持,支持三个级别:TCP、HTTP、JSONRPC
    
    //go的RPC只支持GO开发的服务器与客户端之间的交互,因为采用了gob编码
    
     
    
    //注意字段必须是导出
    
    type Params struct {
    
      Width, Height int;
    
    }
    
     
    
    type Rect struct{}
    
     
    
    //函数必须是导出的
    
    //必须有两个导出类型参数
    
    //第一个参数是接收参数
    
    //第二个参数是返回给客户端参数,必须是指针类型
    
    //函数还要有一个返回值error
    
    func (r *Rect) Area(p Params, ret *int) error {
    
      *ret = p.Width * p.Height;
    
      return nil;
    
    }
    
     
    
    func (r *Rect) Perimeter(p Params, ret *int) error {
    
      *ret = (p.Width + p.Height) * 2;
    
      return nil;
    
    }
    
     
    
    func main() {
    
      rect := new(Rect);
    
      //注册一个rect服务
    
      rpc.Register(rect);
    
      //把服务处理绑定到http协议上
    
      rpc.HandleHTTP();
    
      err := http.ListenAndServe(":8080", nil);
    
      if err != nil {
    
        log.Fatal(err);
    
      }
    
    } 
    
    

    客户端:

    package main;
    
     
    
    import (
    
      "net/rpc"
    
      "log"
    
      "fmt"
    
    )
    
     
    
    type Params struct {
    
      Width, Height int;
    
    }
    
     
    
    func main() {
    
      //连接远程rpc服务
    
      rpc, err := rpc.DialHTTP("tcp", "127.0.0.1:8080");
    
      if err != nil {
    
        log.Fatal(err);
    
      }
    
      ret := 0;
    
      //调用远程方法
    
      //注意第三个参数是指针类型
    
      err2 := rpc.Call("Rect.Area", Params{50, 100}, &ret);
    
      if err2 != nil {
    
        log.Fatal(err2);
    
      }
    
      fmt.Println(ret);
    
      err3 := rpc.Call("Rect.Perimeter", Params{50, 100}, &ret);
    
      if err3 != nil {
    
        log.Fatal(err3);
    
      }
    
      fmt.Println(ret);
    
    } 
    
    

    二、基于tcp的RPC

    服务端:

    package main;
    
     
    
    import (
    
      "net"
    
      "log"
    
      "net/rpc"
    
    )
    
     
    
    //注意字段必须是导出
    
    type Params struct {
    
      Width, Height int;
    
    }
    
     
    
    type Rect struct{}
    
     
    
    func (r *Rect) Area(p Params, ret *int) error {
    
      *ret = p.Width * p.Height;
    
      return nil;
    
    }
    
     
    
    func (r *Rect) Perimeter(p Params, ret *int) error {
    
      *ret = (p.Width + p.Height) * 2;
    
      return nil;
    
    }
    
     
    
    func chkError(err error) {
    
      if err != nil {
    
        log.Fatal(err);
    
      }
    
    }
    
     
    
    func main() {
    
      rect := new(Rect);
    
      //注册rpc服务
    
      rpc.Register(rect);
    
      //获取tcpaddr
    
      tcpaddr, err := net.ResolveTCPAddr("tcp4", "127.0.0.1:8080");
    
      chkError(err);
    
      //监听端口
    
      tcplisten, err2 := net.ListenTCP("tcp", tcpaddr);
    
      chkError(err2);
    
      //死循环处理连接请求
    
      for {
    
        conn, err3 := tcplisten.Accept();
    
        if err3 != nil {
    
          continue;
    
        }
    
        //使用goroutine单独处理rpc连接请求
    
        go rpc.ServeConn(conn);
    
      }
    
    } 
    
    

    客户端: 

    package main;
    
     
    
    import (
    
      "net/rpc"
    
      "fmt"
    
      "log"
    
    )
    
     
    
    type Params struct {
    
      Width, Height int;
    
    }
    
     
    
    func main() {
    
      //连接远程rpc服务
    
      //这里使用Dial,http方式使用DialHTTP,其他代码都一样
    
      rpc, err := rpc.Dial("tcp", "127.0.0.1:8080");
    
      if err != nil {
    
        log.Fatal(err);
    
      }
    
      ret := 0;
    
      //调用远程方法
    
      //注意第三个参数是指针类型
    
      err2 := rpc.Call("Rect.Area", Params{50, 100}, &ret);
    
      if err2 != nil {
    
        log.Fatal(err2);
    
      }
    
      fmt.Println(ret);
    
      err3 := rpc.Call("Rect.Perimeter", Params{50, 100}, &ret);
    
      if err3 != nil {
    
        log.Fatal(err3);
    
      }
    
      fmt.Println(ret);
    
    } 
    
    

    三、JSON RPC 方式

    jsonrpc方式是数据编码采用了json,而不是gob编码。

    服务端:

    package main;
    
     
    
    import (
    
      "net"
    
      "log"
    
      "net/rpc"
    
      "net/rpc/jsonrpc"
    
    )
    
     
    
    //注意字段必须是导出
    
    type Params struct {
    
      Width, Height int;
    
    }
    
     
    
    type Rect struct{}
    
     
    
    func (r *Rect) Area(p Params, ret *int) error {
    
      *ret = p.Width * p.Height;
    
      return nil;
    
    }
    
     
    
    func (r *Rect) Perimeter(p Params, ret *int) error {
    
      *ret = (p.Width + p.Height) * 2;
    
      return nil;
    
    }
    
     
    
    func chkError(err error) {
    
      if err != nil {
    
        log.Fatal(err);
    
      }
    
    }
    
     
    
    func main() {
    
      rect := new(Rect);
    
      //注册rpc服务
    
      rpc.Register(rect);
    
      //获取tcpaddr
    
      tcpaddr, err := net.ResolveTCPAddr("tcp4", "127.0.0.1:8080");
    
      chkError(err);
    
      //监听端口
    
      tcplisten, err2 := net.ListenTCP("tcp", tcpaddr);
    
      chkError(err2);
    
      for {
    
        conn, err3 := tcplisten.Accept();
    
        if err3 != nil {
    
          continue;
    
        }
    
        //使用goroutine单独处理rpc连接请求
    
        //这里使用jsonrpc进行处理
    
        go jsonrpc.ServeConn(conn);
    
      }
    
    } 
    
    

    客户端:

     package main;
    
     
    
    import (
    
      "fmt"
    
      "log"
    
      "net/rpc/jsonrpc"
    
    )
    
     
    
    type Params struct {
    
      Width, Height int;
    
    }
    
     
    
    func main() {
    
      //连接远程rpc服务
    
      //这里使用jsonrpc.Dial
    
      rpc, err := jsonrpc.Dial("tcp", "127.0.0.1:8080");
    
      if err != nil {
    
        log.Fatal(err);
    
      }
    
      ret := 0;
    
      //调用远程方法
    
      //注意第三个参数是指针类型
    
      err2 := rpc.Call("Rect.Area", Params{50, 100}, &ret);
    
      if err2 != nil {
    
        log.Fatal(err2);
    
      }
    
      fmt.Println(ret);
    
      err3 := rpc.Call("Rect.Perimeter", Params{50, 100}, &ret);
    
      if err3 != nil {
    
        log.Fatal(err3);
    
      }
    
      fmt.Println(ret);
    
    } 
    
    
    js