RPC定义

RPC(Remote Procedure Call,远程过程调用)是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络细节的应用程序通信协议。
简单的说就是要像调用本地函数一样调用服务器的函数。

RPC协议构建于TCP或UDP,或者是 HTTP之上,允许开发者直接调用另一台计算机上的程序,而开发者无需额外地为这个调用过程编写网络通信相关代码,
使得开发包括网络分布式程序在内的应用程序更加容易。

http版本的RPC版

语言的RPC包的路径为net/rpc,也就是放在了net包目录下面,由此我们可以推测该RPC包是建立在net包基础之上。

service RPC 实例

package main

import (
        "fmt"
        "log"
        "net"
        "net/rpc"
)
// 定义 HelloService struct {}
type HelloService struct {}
// 给 HelloService 增加 SayHello 方法
func (p HelloService) SayHello(r string, re *string) error {
        *re = "service respone: "  + r
        return nil
}

func main () {
		// 注册 HelloService 服务
        rpc.RegisterName("HelloService", new(HelloService))
		// 监听 port 1234 端口
        listen, err := net.Listen("tcp",":1234")
        if err != nil {
                log.Fatal("ListenTCP error",err)
        }

        fmt.Println("service start ...")
		// 接受 client 端 http连接请求
        conn, err := listen.Accept()
        if err != nil {
                log.Fatal("Accept error",err)
        }
        rpc.ServeConn(conn)

        fmt.Println("service exit..")
}

rpc.Register函数调用会将对象类型中所有满足RPC规则的对象方法注册为RPC函数,
所有注册的方法会放在“HelloService”服务空间之下。
通过rpc.ServeConn函数在该TCP链接上为对方提供RPC服务。

client RPC 实例

package main

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

func main() {
        client, err := rpc.Dial("tcp","localhost:1234")
        if err != nil {
                log.Fatal("client dial error",err)
        }

        var reply string
        err = client.Call("HelloService.SayHello","client send info ",&reply)
        if err != nil {
                log.Fatal("client call error",err)
        }

        fmt.Println("client recv -> ",reply)
}

通过rpc.Dial拨号RPC服务,然后通过client.Call调用具体的RPC方法。
在调用client.Call时,
第一个参数是用点号链接的RPC服务名字和方法名字,“HelloService.SayHello”
第二个参数是客户端发送的信息"client send info "
第三个参数接受服务端返回信息&reply

http RCP 验证测试

  • 首先运行 service 端程序
~/gomod/src/rpc$ go run serverHttpRpc.go 
service start ...
service exit..
  • 运行client 程序:
~/gomod/src/rpc$ go run clientHttpRpc.go 
client recv ->  service respone: client send info 

JSON版本RPC 实例

server jsonRPC 样例

net/rpc/jsonrpc库实现RPC方法,此方式实现的RPC方法支持跨语言调用.

package main

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

type RectRequest struct {
	W int
	H int
}

type Rect struct{}
// Rect 添加 Area 方法
func(this *Rect) Area(p RectRequest, res *int) error {
	*res =p.W * p.H
	return nil
}
// Rect 添加 Perimeter 方法
func(this *Rect) Perimeter(p RectRequest, res *int) error {
	*res = (p.W + p.H) *2
	return nil
}


func main () {
	// 注册 rcp 对象 Rect
	rpc.Register(new(Rect))

	list, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
		log.Fatal("fatal error: ", err)
	}

	fmt.Fprintf(os.Stdout, "%s", "start service listen\n")
	var incomingCount int 
	incomingCount = 0

	for {
		conn, err := list.Accept()
		if err != nil {
			continue
		}
		incomingCount++

		go func(conn net.Conn) {
			fmt.Printf("new client in coming: %d  \n",incomingCount)
			jsonrpc.ServeConn(conn)	// 执行 jsonrpc
		}(conn)
	}
}

client jsonRPC 样例

package main

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


type Params struct {
    W , H int
}


func main() {
    //连接远程rpc服务, jsonrpc.Dial
    conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8080")
    if err != nil {
        log.Fatal(err)
    }

    //调用远程方法
    var ret int
    params := Params{150,100}
    err = conn.Call("Rect.Area", params, &ret)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Rect.Area res: ", ret)


    err = conn.Call("Rect.Perimeter", Params{150, 100}, &ret)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Rect.Perimeter res: ", ret)
}

jsonRPC 验证测试

启动 服务端

robot@ubuntu:~/gomod/src/rpc$ go run serverJsonRpc.go 
start service listen
new client in coming: 1  
new client in coming: 2  
new client in coming: 3  
new client in coming: 4  

启动客户端,内容如下

robot@ubuntu:~/gomod/src/rpc$ go run clientJsonRpc.go 
Rect.Area res:  15000
Rect.Perimeter res:  500
robot@ubuntu:~/gomod/src/rpc$ go run clientJsonRpc.go 
Rect.Area res:  15000
Rect.Perimeter res:  500
robot@ubuntu:~/gomod/src/rpc$ go run clientJsonRpc.go 
Rect.Area res:  15000
Rect.Perimeter res:  500
robot@ubuntu:~/gomod/src/rpc$ go run clientJsonRpc.go 
Rect.Area res:  15000
Rect.Perimeter res:  500