概述
筚路蓝缕,以启山林。抚有蛮夷,以属华夏。不鸣则已,一鸣惊人。
——《左传`宣公十二年》
rpc:远程过程调用,是一个思想,一个概念。核心是分布式应用间通信,屏蔽不同语言,解耦(个人认为)。
net/rpc包是一个go自带的rpc实现方式,可以基于tcp、http、json rpc等方式进行调用。
gRpc基于Netty HTTP/2协议栈封装底层通信,启动时启动一个Netty server。
特别提醒(踩坑后可以返回来再看):如果没有用go module模式,那么需要在src下手动创建google.golang.org目录并进入该目录手动执行git clone https://e.coding.net/robinqiwei/googleprotobuf.git protobuf,否则包不能正确拉取(报找不到google.golang.org/protobuf/proto...等一堆错);如果用的go module模式,那么这个是自动完成的,无需手动创建。
目录
net/rpc
google.golang.org/grpc
net/rpc
实践目标:server端与client端可以实现通信。此实例采用TCP方式调用。项目目录结构:
pub.go
package base1_public
import (
"fmt"
"net/rpc"
)
const HelloServiceName = "pkg.HelloService"
type HelloServiceInterface interface {
HelloS(request string, reply *string) error // 之所以命名为HelloS,是为了验证与其对应之处
}
func RegisterHelloService(svc HelloServiceInterface) error {
return rpc.RegisterName(HelloServiceName, svc)
}
type HelloService struct{}
func (p *HelloService) HelloS(request string, reply *string) error {
*reply = "hello:" + request
fmt.Println("服务端回复:", *reply)
return nil
}
服务端
package main
import (
"log"
"net"
"net/rpc"
"rpc-test/base1_public"
)
func main() {
base1_public.RegisterHelloService(new(base1_public.HelloService))
listener, err := net.Listen("tcp", ":3234")
if err != nil {
log.Fatal("ListenTCP error:", err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal("Accept error:", err)
}
go rpc.ServeConn(conn) // 此次server被终止时才会执行下次循环继续开启新的server,否则一直阻塞等待
}
}
客户端
package main
import (
"fmt"
"log"
"net/rpc"
"rpc-test/base1_public"
)
type HelloServiceClient struct {
*rpc.Client
}
func DialHelloService(network, address string) (*HelloServiceClient, error) {
c, err := rpc.Dial(network, address)
if err != nil {
return nil, err
}
return &HelloServiceClient{Client: c}, nil
}
func (p *HelloServiceClient) start(request string, reply *string) error {
// 方式1
//return p.Client.Call(base1_public.HelloServiceName+".HelloS", request, reply) // HelloS与接口的方法名对应即可
// 方式2
helloCall := p.Client.Go(base1_public.HelloServiceName+".HelloS", request, reply, nil)
//helloCall = <-helloCall.Done
return (<-helloCall.Done).Error
//if err := helloCall.Error; err != nil {
// log.Fatal(err)
//}
}
func main() {
client, err := DialHelloService("tcp", "localhost:3234")
if err != nil {
log.Fatal("dialing:", err)
}
var reply string
err = client.start("哈哈哈", &reply)
if err != nil {
log.Fatal(err)
}
fmt.Println("收到的回复:", reply)
}
分别启动服务端和客户端,控制台分别如下:
服务端回复: hello:哈哈哈
收到的回复: hello:哈哈哈
http、json-rpc等方式的调用可移步:go语言net包rpc远程调用的使用--http、json-rpc、tcp_秋天的博客-CSDN博客
google.golang.org/grpc
实践目标:服务端有两个服务,客户端我要使用(调用)这两个服务。
背景设计:远端某个地方有两个服务:分别是加密服务和解密服务,client调用时只需传明文或密文作为参数即可。
项目结构如下:
通过.proto文件约定好服务接口、参数等,通过工具protoc-gen-go生成客户端和服务端共用的对照表。
secret.proto
syntax = "proto3";
package proto;
service SecretService {
rpc Encrypt(SecretRequest) returns (SecretResponse) {}
rpc Decrypt(SecretRequest) returns (SecretResponse) {}
}
message SecretRequest {
string request = 1;
}
message SecretResponse {
string response = 1;
}
生成的secret.pb.go挺长,这里就不贴了。生成方式及环境搭建可移步搭建protobuf+gRpc环境并验证_七里香-CSDN博客_grpc环境
插件生成方式请移步:
go生成grpc代码插件的方法总结__七里香的博客-CSDN博客go生成grpc代码插件的方法总结https://blog.csdn.net/HYZX_9987/article/details/125320328?spm=1001.2014.3001.5501
服务端
package main
import (
"context"
"encoding/base64"
"fmt"
pt "gRpc-demo/proto"
"google.golang.org/grpc"
"log"
"net"
)
const PORT = "9001"
type SecretServiceStruct struct{}
// 加密服务 简单点直接b64编码
func (s *SecretServiceStruct) Encrypt(ctx context.Context, r *pt.SecretRequest) (*pt.SecretResponse, error) {
log.Print("调用了加密服务:", r.Request)
secret := base64.StdEncoding.EncodeToString([]byte(r.Request))
return &pt.SecretResponse{Response: r.GetRequest() + "加密成功:" + secret}, nil
}
// 解密服务
func (s *SecretServiceStruct) Decrypt(ctx context.Context, r *pt.SecretRequest) (*pt.SecretResponse, error) {
log.Print("调用了解密服务:", r.Request)
str, err := base64.StdEncoding.DecodeString(r.Request)
if err != nil {
log.Fatalf("服务端解密失败: %v", err.Error())
return &pt.SecretResponse{Response: ""}, err
}
return &pt.SecretResponse{Response: r.GetRequest() + "解密成功:" + string(str)}, nil
}
func main() {
server := grpc.NewServer()
pt.RegisterSecretServiceServer(server, &SecretServiceStruct{})
lis, err := net.Listen("tcp", ":"+PORT)
if err != nil {
log.Fatalf("net.Listen err: %v", err)
}
addr := fmt.Sprintf("%s", lis.Addr())
log.Printf("Listening on %v", addr)
log.Fatal(server.Serve(lis))
}
客户端
package main
import (
"context"
pt "gRpc-demo/proto"
"google.golang.org/grpc"
"log"
"strings"
)
const PORT = "9001"
var str = `this is gRpc`
func main() {
// 上面gRPC的服务没有提供证书支持,因此客户端在连接服务器中通过grpc.WithInsecure()选项跳过对服务器证书的验证
conn, err := grpc.Dial(":"+PORT, grpc.WithInsecure())
if err != nil {
log.Fatalf("grpc.Dial err: %v", err)
}
defer conn.Close()
client := pt.NewSecretServiceClient(conn)
resp0, err := client.Encrypt(context.Background(), &pt.SecretRequest{
Request: str,
})
if err != nil {
log.Fatalf("client.Encrypt err: %v", err)
}
secretStr := strings.Split(resp0.GetResponse(), ":")[1]
log.Printf("请求加密服务: %s", secretStr)
resp1, err := client.Decrypt(context.Background(), &pt.SecretRequest{
Request: secretStr,
})
if err != nil {
log.Fatalf("client.Decrypt err: %v", err)
}
resStr := strings.Split(resp1.GetResponse(), ":")[1]
log.Printf("请求解密服务: %s", resStr)
}
分别启动服务端、客户端,控制台分别如下:
服务端:
2020/06/01 09:41:20 Listening on [::]:9001
2020/06/01 09:41:37 调用了加密服务:this is gRpc
2020/06/01 09:41:37 调用了解密服务:dGhpcyBpcyBnUnBj
客户端:
2020/06/01 09:41:37 请求加密服务: dGhpcyBpcyBnUnBj
2020/06/01 09:41:37 请求解密服务: this is gRpc
最后
以上就是热情身影为你收集整理的分别以google.golang.org/grpc和net/rpc理解RPC的全部内容,希望文章能够帮你解决分别以google.golang.org/grpc和net/rpc理解RPC所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复