Protobuf和GRPC实现远程服务调用(二)

10 篇文章 0 订阅

一、gRPC介绍

gRPC是Google公司发布的一个开源的、高性能的、跨语言的RPC框架,它是基于HTTP2、Protobuf3.x、Netty4.x实现的。

与其他RPC的实现原理相似,gPRC的实现也是按照以下几个步骤:

  1. 定义服务接口,指定远程调用方法;
  2. 在服务端实现服务接口,并运行一个gRPC服务器来处理客户端的调用;
  3. 在客户端调用服务端的方法;

gRPC支持在不同语言环境下的运行和交互。例如你可以使用Java创建一个gRPC的服务端,使用Go创建它的客户端。在这里插入图片描述
此外,在Google最新API中将有gRPC版本的接口,使得开发人员很容易地将Google的功能集成到你的应用中。

二、gRPC环境搭建

第一步:执行下面命令克隆grpc-go代码库;

go get google.golang.org/grpc

第二步:启动服务端;

$ cd $GOPATH/src/google.golang.org/grpc/examples/helloworld/greeter_server
$ go run main.go

第三步:在另外一个终端启动客户端;

$ cd $GOPATH/src/google.golang.org/grpc/examples/helloworld/greeter_client
$ go run main.go

运行效果:
在这里插入图片描述

三、源码剖析

(1)服务端源码阅读

// 定义服务端监听的端口
const (
        port = ":50051"
)

// 定义服务对象变量,该对象实现了helloworld.GreeterServer接口
type server struct{}

// 实现helloworld.GreeterServer接口的SayHello方法,该方法会与server服务对象一起发布出去
// 参数一:当前的上下文环境
// 参数二:客户端发送过来的消息
// 返回值一:服务端返回的消息
// 返回值二:异常对象
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
        return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func main() {
		// 定义监听器,用于监听客户端的连接
        lis, _:= net.Listen("tcp", port)
        
        // 注册服务对象
        s := grpc.NewServer()
        pb.RegisterGreeterServer(s, &server{})
        
        // 在gRPC服务端注册反射服务(为什么要注册反射服务,后面做深入了解的时候再补充)
        reflection.Register(s)
        ....
}

(2)客户端源码阅读

func main() {
        // 创建服务器连接
        conn, _ := grpc.Dial(address, grpc.WithInsecure())
        defer conn.Close()
        
        // 创建gRPC客户端
        c := pb.NewGreeterClient(conn)
        
        // 如果运行客户端时候没有传入参数,那么就使用默认值作为调用服务方法的实参
        name := defaultName
        if len(os.Args) > 1 {
                name = os.Args[1]
        }
        
        // 调用服务方法,并且把当前上下文环境对象,以及HelloRequest传入方法中
        r, _ := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
        
        // 打印服务端返回的数据
        log.Printf("Greeting: %s", r.Message)
}

四、Go实现gRPC远程调用

我们模拟上面的示例在Windows环境下实现gPRC远程调用服务的功能。

第一步:在$GOPATH/src目录下新建/Project016/myproto文件夹。

cd $GOPATH/src
md \Project016\myproto

第二步:进入到myproto文件夹下,然后新建test.proto文件。文件内容如下:

syntax = "proto3";

package grpc_test;

service HelloServer {
    rpc SayHello(HelloRequest) returns (HelloReply) {}
    rpc GetHelloMsg(HelloRequest) returns (HelloMessage) {}
}

message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}

message HelloMessage {
    string msg = 1;
}

注意:包名不能够以数字开头,否则会提示错误。
在这里插入图片描述
第三步:进入proto文件所在目录,执行以下命令编译文件。

protoc --go_out=plugins=grpc:./ test.proto

编译后在当前文件夹下会生成一个test.pb.go的文件。

第四步:在项目下新建一个go文件,实现grpc服务端功能。

package main

import (
	pt "Project016/myproto"
	"context"
	"google.golang.org/grpc"
	"net"
	"fmt"
)

const (
	port = "127.0.0.1:10086"
)

// 定义服务对象的变量
type server struct {}

// 实现HelloServer.SayHello方法
func (this *server) SayHello(ctx context.Context, in *pt.HelloRequest) (*pt.HelloReply, error) {
	msg := "hello" + in.Name
	return &pt.HelloReply{Message: msg}, nil
}

// 实现HelloServer.GetHelloMsg方法
func (this *server) GetHelloMsg(ctx context.Context, in *pt.HelloRequest) (*pt.HelloMessage, error) {
	return &pt.HelloMessage{Msg: "this is from server HAHA!"}, nil
}

func main() {
	// 定义监听器
	ln ,err := net.Listen("tcp", port)
	if err!=nil {
		fmt.Println("网络异常",err)
	}
	
	// 注册服务对象
	srv:= grpc.NewServer()
	pt.RegisterHelloServerServer(srv,&server{})
	
	// 监听grpc服务
	err= srv.Serve(ln)
}

第五步:新建另外一个go文件,实现grpc客户端功能。

package main


import (
	"google.golang.org/grpc"
	pt "Project016/myproto"
	"fmt"
	"context"
)

// 定义服务端的地址
const (
	server_port = "127.0.0.1:10086"
)

func main() {
	// 连接服务器
	conn, err := grpc.Dial(server_port, grpc.WithInsecure())
	if err != nil {
		fmt.Println("连接服务器失败", err)
	}
	defer conn.Close()
	// 创建gRPC客户端
	cli := pt.NewHelloServerClient(conn)

	// 远程调用HelloServer服务的SayHello方法
	r1, err := cli.SayHello(context.Background(), &pt.HelloRequest{Name: "panda"})
	if err != nil {
		fmt.Println("Sorry, can not get SayHello server!")
		return
	}
	// 打印服务器返回的消息
	fmt.Println("r1 = ", r1.Message)

	// 远程调用HelloServer服务的GetHelloMsg方法
	r2, err := cli.GetHelloMsg(context.Background(), &pt.HelloRequest{Name: "panda"})
	if err != nil {
		fmt.Println("Sorry, can not get GetHelloMsg server!")
		return
	}
	// 打印服务器返回的消息
	fmt.Println("r2 = ", r2.Msg)
}

第六步:启动服务端和客户端。运行效果如下图所示:
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值