一、go rpc

rpc(remote procedure call) 远程过程调用。像调用本地函数一样,调用远程函数。
data.go:定义请求参数与响应数据

package data

type RequestParm struct {
	Parm1 int
	Parm2 int
}

type ResponseData struct {
	Resut string
}

service.go:定义服务

package service

import (
	"fmt"
	"gorpc/gorpc/data"
)

type SomeServer int

func (s *SomeServer) DoSomeServe(request *data.RequestParm, response *data.ResponseData) error {
	fmt.Printf("request parm is %v", request)
	response.Resut = fmt.Sprintf("client request parm is %v", request)
	return nil
}

1、http rpc

以 http 协议通信
client.go

package main

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

func main() {
	// rpc http client 请求
	clint, err := rpc.DialHTTP("tcp", "localhost:8989")
	if err != nil {
		log.Fatal(err)
	}

	parm := &data.RequestParm{Parm1: 1, Parm2: 2}
	result := &data.ResponseData{}

	// 调用远程服务
	err = clint.Call("SomeServer.DoSomeServe", parm, result)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("request parm is %v, response is %v", parm, result)
}

server.go

package main

import (
	"gorpc/gorpc/service"
	"log"
	"net/http"
	"net/rpc"
)

func main() {
	someserver := new(service.SomeServer)
	// 注册服务
	rpc.Register(someserver)
	// 注册到http server服务上
	rpc.HandleHTTP()
	// 监听http请求
	err := http.ListenAndServe(":8989", nil)
	if err != nil {
		log.Fatal(err)
	}

}

2、tcp rpc

以 tcp 协议通信
client.go

package main

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

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

	parm := &data.RequestParm{Parm1: 1, Parm2: 2}
	result := &data.ResponseData{}
	// 远程服务请求
	err = client.Call("SomeServer.DoSomeServe", parm, result)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("request parm is %v, response is %v", parm, result)
}

server.go

package main

import (
	"gorpc/gorpc/service"
	"log"
	"net"
	"net/rpc"
)

func main() {
	server := new(service.SomeServer)
	// 注册rpc服务
	rpc.Register(server)

	tcpAddr, err := net.ResolveTCPAddr("tcp", "localhost:8989")
	if err != nil {
		log.Fatal(err)
	}
	// tcp 监听器
	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		log.Fatal(err)
	}

	for {
		// 接受请求
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}
		// 服务请求处理
		go rpc.ServeConn(conn)
	}
}

3、json rpc

client.go

package main

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

func main() {
	client, err := jsonrpc.Dial("tcp", "localhost:8989")
	if err != nil {
		log.Fatal(err)
	}

	parm := &data.RequestParm{Parm1: 1, Parm2: 2}
	result := &data.ResponseData{}

	err = client.Call("SomeServer.DoSomeServe", parm, result)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("request parm is %v, response is %v", parm, result)
}

server.go

package main

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

func main() {
	server := new(service.SomeServer)
	rpc.Register(server)

	tcpAddr, err := net.ResolveTCPAddr("tcp", "localhost:8989")
	if err != nil {
		log.Fatal(err)
	}
	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}
		go jsonrpc.ServeConn(conn)
	}
}
二、gRPC

1、安装 Protocol Buffers 工具

Protocol Buffers 下载合适的版本,

我用的windows protoc-21.12-win64.zip
,下载解压后把 protoc\bin 设置为环境

2、安装 protoc-gen-go 工具

go install google.golang.org/protobuf/cmd/protoc-gen-go

3、安装 protoc-gen-go-grpc 工具

go install google.golang.org/grpc/cmd/protoc-gen-go-grpc

4、protobuf 协议定义

hello.proto

// proto 版本
syntax="proto3";
// 编译为go文件时,go的package
option go_package="./protocol";
// proto package
package protocol;
// 定义服务
service SomeServer{
    rpc DoSomeServe(RequestParm)returns(ResponseData){}
}
// 定义参数
message RequestParm{
    int64 Parm1=1;
    int64 Parm2=2;
}
message ResponseData{
    string Resut=1;
}

在 hello.proto 同目录下执行命令:

protoc --go_out=.  --go-grpc_out=. ./*.proto

生成 hello_grpc.pb.go 和 hello.pb.go

5、go 实现 protobuf 协议定义的 server

server.go

package main

import (
	"context"
	"fmt"
	pt "gorpc/grpc/protocol/protocol"
	"log"
	"net"

	"google.golang.org/grpc"
)

const (
	srvAddr = "localhost:8989"
)

// UnimplementedSomeServerServer must be embedded to have forward compatible implementations
type server struct {
	pt.UnimplementedSomeServerServer
}

// 实现rpc DoSomeServe
func (s *server) DoSomeServe(ctx context.Context, in *pt.RequestParm) (*pt.ResponseData, error) {
	return &pt.ResponseData{Resut: fmt.Sprintf("client request parm is %v", in)}, nil
}

func main() {
	// 监听网络请求
	ln, err := net.Listen("tcp", srvAddr)
	if err != nil {
		log.Fatal(err)
	}

	// 创建rpc句柄
	srv := grpc.NewServer()
	// 注册服务
	pt.RegisterSomeServerServer(srv, &server{})

	err = srv.Serve(ln)

	if err != nil {
		log.Fatal(err)
	}

}

6、rpc 客户端调用

package main

import (
	"context"
	"fmt"
	pt "gorpc/grpc/protocol/protocol"
	"log"

	"google.golang.org/grpc"
)

const (
	srvAddr = "localhost:8989"
)

func main() {
	// 连接 rpc 服务
	conn, err := grpc.Dial(srvAddr, grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	// 获取rpc客户端
	c := pt.NewSomeServerClient(conn)
	// 调用rpc函数
	response, err := c.DoSomeServe(context.Background(), &pt.RequestParm{Parm1: 1, Parm2: 2})

	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("response.Resut:", response.Resut)

}
三、RPC 通信链路