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 通信链路