net and rpc package in golang Overview of Summary

  • 2020-06-12 09:22:32
  • OfStack

RPC, or Remote Procedure Call (remote procedure call), is colloquial 1 for invoking a service on a remote machine as if it were a local service 1.
My project adopts the micro-service architecture based on Restful. As the communication between micro-services becomes more and more frequent and consumes more and more system resources, I hope to use rpc for internal communication and Restful for external communication. This leads to the rpc package for the golang standard library and grpc for google.

This article focuses on 1 golang rpc package.

introduce

rpc of golang supports three levels of RPC: TCP, HTTP, JSONRPC. However, Go's RPC package is the only RPC without two. Unlike the traditional RPC system, it only supports the interaction between the server and the client developed by Go, because internally, they are encoded by Gob.

The functions of Go RPC can only be accessed remotely if they meet the following conditions, otherwise they will be ignored. The detailed requirements are as follows:

Functions must be exported (uppercase) You must have two parameters of the exported type, The first parameter is the received parameter, the second parameter is the one returned to the client-client side, and the second parameter must be of pointer type The function also has one return value, error

For example, the correct RPC function format is as follows:


func (t *T) MethodName(argType T1, replyType *T2) error

T, T1 and T2 types must be able to be encoded and decoded by encoding/gob packages.

The sample

Take an example of http.

Here's the code for the http server:


package main

import (
  "errors"
  "net"
  "net/rpc"
  "log"
  "net/http"
)

type Args struct {
  A, B int
}

type Quotient struct {
  Quo, Rem int
}

type Arith int

func (t *Arith) Multiply(args *Args, reply *int) error {
  *reply = args.A * args.B
  return nil
}

func (t *Arith) Divide(args *Args, quo *Quotient) error {
  if args.B == 0 {
    return errors.New("divide by zero")
  }
  quo.Quo = args.A / args.B
  quo.Rem = args.A % args.B
  return nil
}

func main() {
  arith := new(Arith)
  rpc.Register(arith)
  rpc.HandleHTTP()
  l, e := net.Listen("tcp", ":1234")
  if e != nil {
    log.Fatal("listen error:", e)
  }
  http.Serve(l, nil)
}

Simple analysis 1 below the above example, first instantiated an Arith object arith, then registered rpc service for arith, then mounted rpc to http service, when http service opened, we can call arith rpc standard method through rpc client.

See the client code:


package main

import (
  "net/rpc"
  "log"
  "fmt"
)

type Args struct {
  A, B int
}

type Quotient struct {
  Quo, Rem int
}

func main() {
  client, err := rpc.DialHTTP("tcp", "127.0.0.1:1234")
  if err != nil {
    log.Fatal("dialing:", err)
  }

  // Synchronous call
  args := &Args{7,8}
  var reply int
  err = client.Call("Arith.Multiply", args, &reply)
  if err != nil {
    log.Fatal("arith error:", err)
  }
  fmt.Printf("Arith: %d*%d=%d\n", args.A, args.B, reply)

  // Asynchronous call
  quotient := new(Quotient)
  divCall := client.Go("Arith.Divide", args, quotient, nil)
  replyCall := <-divCall.Done  // will be equal to divCall
  if replyCall.Error != nil {
    log.Fatal("arith error:", replyCall.Error)
  }
  fmt.Printf("Arith: %d/%d=%d...%d", args.A, args.B, quotient.Quo, quotient.Rem)
  // check errors, print, etc.
}

To explain briefly, first connect the server side with DialHTTP method of rpc, and call the function of the server side will use Call method. The parameters and return value of Call method have clearly expressed the overall call logic of rpc.

We run the server side, then run the client side, the client side will output:


Arith: 7*8=56
Arith: 7/8=0...7

At this point, the entire call logic for rpc is complete.


Related articles: