golang jsonrpc

golang 标准库

client

package main

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

type Args struct {
	A, B int
}

type Arith int

func main() {
	// Create a new jsonrpc client
	//
	// NewClient returns a new rpc.Client to handle requests to the
	// set of services at the other end of the connection.
	//
	// Client will use json as the server's specified codec
	// to encode requests and decode responses.
	// client := jsonrpc.NewClient(conn)

	// Dial connects to a JSON-RPC server at the specified network address.
	client, err := jsonrpc.Dial("tcp", ":9000")
	if err != nil {
		log.Fatalln("Dial error: " + err.Error())
	}

	// Create a new integer `reply`
	var reply int

	// Create a new `Args` type object `args` and
	// set it's `A` and `B` integer values
	args := &Args{A: 10, B: 10}

	// Call the `Arith.Add` method from the rpc server and return
	// a new remote procedure call object `call`
	//
	// Go invokes the function asynchronously. It returns the Call
	// structure representing the invocation. The done channel will signal
	// when the call is complete by returning the same Call object.
	// If done is nil, Go will allocate a new channel.
	// If non-nil, done must be buffered or Go will deliberately crash.
	call := client.Go("Arith.Add", args, &reply, nil)
	if err != nil {
		log.Fatalln("Call error: " + err.Error())
	}

	// Create a select statement to either wait for the remote
	// procedure call's done channel to be filled, letting us know
	// that the call has been completed, otherwise if there is no
	// response after 10 seconds, timeout and print a message
	select {
	case <-call.Done: // Receive that the remote procedure call is done
		// Print out the reply
		fmt.Printf("Arith.Add Async: %d + %d = %d\n", args.A, args.B, reply)
	case <-time.After(10 * time.Second): // Timeout after 10 seconds
		// Print out a timed out message
		fmt.Println("Timed out after 10 seconds.")
	}
}

server

package main

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

type Args struct {
	A, B int
}

type Arith int

func (a *Arith) Add(args *Args, reply *int) error {
	*reply = args.A + args.B
	return nil
}

func main() {
	arith := new(Arith)

	// Create a new server rather than just using the
	// DefaultServer from rpc when no server is created
	//
	// NewServer returns a new Server.
	server := rpc.NewServer()

	// Register `arith` to the rpc server `server`
	//
	// Register publishes in the server the set of methods of the
	// receiver value that satisfy the following conditions:
	//	- exported method of exported type
	//	- two arguments, both of exported type
	//	- the second argument is a pointer
	//	- one return value, of type error
	// It returns an error if the receiver is not an exported type or has
	// no suitable methods. It also logs the error using package log.
	// The client accesses each method using a string of the form
	// "Type.Method", where Type is the receiver's concrete type.
	if err := server.Register(arith); err != nil {
		log.Fatalln(err)
	}

	// Create a new tcp listener on port 9000
	ln, err := net.Listen("tcp", ":9000")
	if err != nil {
		log.Fatalln("Dial error: " + err.Error())
	}
	defer ln.Close()

	for {
		// Accept a connection from tcp listener `ln`
		conn, err := ln.Accept()
		if err != nil {
			log.Fatalln("Accept error: " + err.Error())
		}

		go func(conn net.Conn) {
			defer conn.Close()

			// Call `server.ServeCodec` and call the function
			// `jsonrpc.NewServerCodec(conn)` as it's parameter
			//
			// ServeCodec is like ServeConn but uses the specified codec to
			// decode requests and encode responses.
			//
			// NewServerCodec returns a new rpc.ServerCodec using JSON-RPC on conn.
			server.ServeCodec(jsonrpc.NewServerCodec(conn))
		}(conn)
	}
}