go-gRPC 初体验

栏目: IT技术 · 发布时间: 4年前

内容简介:微服务想必大家都不陌生了。刚接触到示例代码通过目录可以看到这里使用了

微服务想必大家都不陌生了。刚接触到 golang ,那么在 golang 中怎么使用微服务呢。这里使用 gRRC 框架写了一个简单的例子。

环境要求

示例代码 iris-grpc-example

项目结构

iris-grpc-example
│  .gitignore
│  go.mod
│  go.sum
│  README.md
│
├─proto
│      README.md
│      servers.pb.go
│      servers.proto
│
└─servers
        main.go
        services.go

通过目录可以看到这里使用了 go mod ,当前 golang 版本 1.13

proto

使用 Protobuf 定义了通信的IDL,可以理解为 rpc 中接口定义。

  • protocol buf

可扩展的序列化数据结构,在通信协议中使用的比较广泛。比 json 更快,更小。比 xml 更简洁。

servers.proto

syntax = "proto3";
package proto;
message Id {
    int32 id=1;
}
message Name {
    string name=1;
}
message Age {
    int32 age=1;
}
// 用户变量
message User {
    int32 id=1;
    string name=2;
    int32 age=3;
}
// 用户参数
message UserParams{
    Name name=1;
    Age age=2;
}
// 声明那些方法可以使用rpc
service ServiceSearch{
    rpc SaveUser(UserParams) returns (Id){}
    rpc UserInfo(Id) returns (User){}
}

简单说明

syntax = "proto3"; 声明了 proto 语法版本。

package 声明包名

message Id {
    int32 id=1;
}

接口中使用的变量声明 变量名称: Id ,类型: int32 ,等号后面表示字段编号为 1

service ServiceSearch{
    rpc SaveUser(UserParams) returns (Id){}
    rpc UserInfo(Id) returns (User){}
}

声明了两个函数 SaveUser(),UserInfo() 是使用 RPC 协议,接收的参数与返回参数分别为什么。

servers.go

该文件是使用 servers.proto 编译生成的

。在完成 servers.proto 之后 在 proto 目录下执行

protoc --go_out=plugins=grpc:. *.proto

Protoc plugin-go
grpc

编译命令执行完之后,就会生成 servers.go 。而我们在 go 的模块中实际使用的代码也就是这个文件。

如果有兴趣的同学可以看看里面的代码,主要就是一些参数定义【 我们在proto中所定义的 】,还有一个接口的声明。

......
// ServiceSearchServer is the server API for ServiceSearch service.
type ServiceSearchServer interface {
    SaveUser(context.Context, *UserParams) (*Id, error)
    UserInfo(context.Context, *Id) (*User, error)
}

// UnimplementedServiceSearchServer can be embedded to have forward compatible implementations.
type UnimplementedServiceSearchServer struct {
}

func (*UnimplementedServiceSearchServer) SaveUser(ctx context.Context, req *UserParams) (*Id, error) {
    return nil, status.Errorf(codes.Unimplemented, "method SaveUser not implemented")
}
func (*UnimplementedServiceSearchServer) UserInfo(ctx context.Context, req *Id) (*User, error) {
    return nil, status.Errorf(codes.Unimplemented, "method UserInfo not implemented")
}

func RegisterServiceSearchServer(s *grpc.Server, srv ServiceSearchServer) {
    s.RegisterService(&_ServiceSearch_serviceDesc, srv)
}
......

可以看到最后有一个 RegisterServiceSearchServer 注册服务的方法,接受一个 grpc.Server 与一个 ServiceSearchServer 的接口。而我们在 servers/services.go 中,主要就是实现 ServiceSearchServer 这个接口,并通过 RegisterServiceSearchServer 将接口实现的函数注册 rpc 服务中。

servers

rpc 接口的实现与调用

services.go 接口的实现

package main

import (
    "context"
    "fmt"
    "google.golang.org/grpc"
    "iris-grpc-example/proto"
    "log"
    "math/rand"
    "net"
)

type ServiceSearch struct{}

func main() {
    listen, err := net.Listen("tcp", "127.0.0.1:9527")
    if err != nil {
        log.Fatalf("tcp listen failed:%v", err)
    }
    server := grpc.NewServer()
    fmt.Println("services start success")
    proto.RegisterServiceSearchServer(server, &ServiceSearch{})
    server.Serve(listen)

}

//保存用户
func (Service *ServiceSearch) SaveUser(ctx context.Context, params *proto.UserParams) (*proto.Id, error) {
    id := rand.Int31n(10) //随机生成id 模式保存成功
    res := &proto.Id{Id: id}
    fmt.Printf("username:%s,age:%d\r\n", params.Name, params.Age)
    return res, nil
}

func (Service *ServiceSearch) UserInfo(ctx context.Context, id *proto.Id) (*proto.User, error) {
    res := &proto.User{Id:id.GetId(),Name:"test",Age:31}
    return res, nil
}
  • 实现 ServiceSearchServer 接口,在代码中声明了一个 ServiceSearch 来实现了 ServiceSearchServer 接口。
  • SaveUser ,实现了 proto 中定义的 SaveUser 方法,需要注意的是这里需要返回两个参,数第一个是我们预先定好的参数,第二个为定义的错误信息。
  • main 函数声明当前服务的ip以及端口,并创建了一个 grpc server 然后通过 proto.RegisterServiceSearchServer(server, &ServiceSearch{})ServiceSearch 注册到 grpc

main.go 接口的调用

package main

import (
    "context"
    "github.com/kataras/iris/v12"
    "google.golang.org/grpc"
    "iris-grpc-example/proto"
    "log"
)

var client proto.ServiceSearchClient

func main() {
    app := iris.New()
    app.Logger().SetLevel("debug") //debug
    app.Handle("GET", "/testSaveUser", saveUser)
    app.Handle("GET", "/testUserInfo", userInfo)
    app.Run(iris.Addr("127.0.0.1:8080"))
}

func saveUser(ctx iris.Context) {
    params := proto.UserParams{}
    params.Age = &proto.Age{Age: 31}
    params.Name = &proto.Name{Name: "test"}
    res, err := client.SaveUser(context.Background(), &params)
    if err != nil {
        log.Fatalf("client.SaveUser err: %v", err)
    }
    ctx.JSON(res)
}
func userInfo(ctx iris.Context) {
    res, err := client.UserInfo(context.Background(), &proto.Id{Id: 1})
    if err != nil {
        log.Fatalf("client.userInfo err: %v", err)
    }
    ctx.JSON(res)
}

func init() {
    connect, err := grpc.Dial("127.0.0.1:9527", grpc.WithInsecure())
    if err != nil {
        log.Fatalln(err)
    }
    client = proto.NewServiceSearchClient(connect)

}

这里使用了 iris 作为了一个 client 。与传统 http 的区别主要是在

func init() {
    connect, err := grpc.Dial("127.0.0.1:9527", grpc.WithInsecure())
    if err != nil {
        log.Fatalln(err)
    }
    client = proto.NewServiceSearchClient(connect)

}

这里创建了一个 rpcclient 。在使用的时候我们只需要调用 services 里面已经写好的函数即可。

测试

\iris-grpc-example>cd servers

开启服务: go run services.go

开启Client: go run main.go

浏览器访问

http://127.0.0.1:8080/testSaveUser
{
"id": 1
}
http://127.0.0.1:8080/testUserInfo
{
"id": 1,
"name": "test",
"age": 31
}

期待一起交流

go-gRPC 初体验


以上所述就是小编给大家介绍的《go-gRPC 初体验》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

游戏化思维

游戏化思维

[美] 凯文·韦巴赫(Kevin Werbach)、[美] 丹·亨特(Dan Hunter) / 周逵、王晓丹 / 浙江人民出版社 / 2014-4 / 36.90

[内容简介] ●本书由开设了全世界第一个游戏化课程的沃顿商学院副教授凯文·韦巴赫和丹·亨特所著,第一次全面系统地介绍游戏化的理论,阐述了如何将游戏的理念应用到商业实践中。 ●作者指出,在商业竞争日益激烈的今天,传统的激励方式渐渐失效,未来的管理将更多地建立在员工和消费者的内在动机和自我激励上。这些制作精良、设计巧妙的游戏建立在多年来对人类动机和人类心理的研究基础之上,可以最大限度地激发......一起来看看 《游戏化思维》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具