golang简单使用gRPC

自闭症网瘾萝莉.ら 提交于 2020-10-05 09:14:26

一. 环境准备。

  1. 安装gprc
go get -u google.golang.org/grpc
  1. 安装protocol buffers
    下载地址: https://github.com/protocolbuffers/protobuf/releases
    下载解压后放入PATH路径下

二. 实现服务端。

  1. 新建account.proto文件。
syntax = "proto3";
// 定义包名
package account;

// 可以定义多个服务,每个服务内可以定义多个接口
service Waiter {
// 定义接口 (结构体可以复用)
// 方法 (请求消息结构体) returns (返回消息结构体) {}

//注册
rpc Register (RegisterReq) returns (RegisterRes) {}
//登录
rpc Login (LoginReq) returns (LoginRes) {}
}

// 定义 Req 消息结构

//注册请求参数
message RegisterReq {
 // 类型 字段 = 标识号
 string username = 1;       //账号
 string password = 2;       //密码
}
//登录请求参数
message LoginReq {
// 类型 字段 = 标识号
string username = 1;    //账号
string password = 2;    //密码
}

// 定义 Res 消息结构

//注册返回参数
message RegisterRes {
 string backJson = 1;
}

//登录返回参数
message LoginRes {
string backJson = 1;
}
  1. 生成golang的服务代码
protoc --go_out=plugins=grpc:. ./account.proto
  1. 实现服务端接口
package account

import (
	"golang.org/x/net/context"
)

// 业务实现方法的容器
type AccountServer struct{}

//模拟账号数据库
var data = make(map[string]string)


//实现注册
func (s *AccountServer) Register(ctx context.Context, in *RegisterReq) (*RegisterRes, error) {
	//账号
	username := in.Username
	//密码
	password := in.Password

	//模拟数据库查询
	_,exist := data[username]
	//判断用户是否存在
	if exist {
		return &RegisterRes{BackJson: "{\"status\":\"0\",\"msg\":\"用户名已存在\"}"}, nil
	}
	//模拟入库
	data[username] = password
	//返回
	return &RegisterRes{BackJson: "{\"status\":\"666\",\"msg\":\"注册成功\"}"}, nil
}


//实现登录
func (s *AccountServer) Login(ctx context.Context, in *LoginReq) (*LoginRes, error) {
	//账号
	username := in.Username
	//密码
	password := in.Password
	//模拟数据库查询
	dataPwd,exist := data[username]
	//验证
	if (!exist || password!=dataPwd) {
		return &LoginRes{BackJson: "{\"status\":\"0\",\"msg\":\"用户名或者密码错误\"}"}, nil
	}
	//返回
	return &LoginRes{BackJson: "{\"status\":\"666\",\"msg\":\"登录成功\",\"data\":{\"token\":\"123456\"}}"}, nil
}
  1. 服务端的main文件
package main

import (
	"log"
	"net"
	"google.golang.org/grpc"
	"grpc/account"
	"google.golang.org/grpc/reflection"
)


func main() {
	lis, err := net.Listen("tcp", ":8028")  //监听所有网卡8028端口的TCP连接
	if err != nil {
		log.Fatalf("监听失败: %v", err)
	}
	s := grpc.NewServer() //创建gRPC服务

	/**注册接口服务
	 * 以定义proto时的service为单位注册,服务中可以有多个方法
	 * (proto编译时会为每个service生成Register***Server方法)
	 * 包.注册服务方法(gRpc服务实例,包含接口方法的结构体[指针])
	 */
	account.RegisterWaiterServer(s, &account.AccountServer{})
	/**如果有可以注册多个接口服务,结构体要实现对应的接口方法
	 * user.RegisterLoginServer(s, &server{})
	 * minMovie.RegisterFbiServer(s, &server{})
	 */
	// 在gRPC服务器上注册反射服务
	reflection.Register(s)
	// 将监听交给gRPC服务处理
	err = s.Serve(lis)
	if  err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

三. 实现客户端。

package admin

import (
	"beegoApp/controllers"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"beegoApp/pb/account"	//从service端复制过来的pb文件
	"beegoApp/common"
)

type LoginController struct {
	controllers.BaseController
}

//注册
func (this *LoginController) Register(){
	// 建立连接到gRPC服务
	conn, err := grpc.Dial("127.0.0.1:8028", grpc.WithInsecure())
	if err != nil {
		this.ErrorJson(666, err.Error())
	}
	// 函数结束时关闭连接
	defer conn.Close()
	// 创建Waiter服务的客户端
	t := account.NewWaiterClient(conn)

	// 模拟请求数据
	username := "test123"
	password := "123456"
	// 调用gRPC接口
	tr, err := t.Register(context.Background(), &account.RegisterReq{Username:username,Password:password})
	if err != nil {
		this.ErrorJson(666, err.Error())
	}
	//json转map
	res := common.JSONToMap(tr.BackJson)

	if (res["status"] == "666"){
		//注册成功
		this.SuccessJson(res["data"])
	}else{
		//注册失败
		this.ErrorJson(123, res["msg"].(string))
	}
}

//登录
func (this *LoginController) Login(){
	// 建立连接到gRPC服务
	conn, err := grpc.Dial("127.0.0.1:8028", grpc.WithInsecure())
	if err != nil {
		this.ErrorJson(666, err.Error())
	}
	// 函数结束时关闭连接
	defer conn.Close()
	// 创建Waiter服务的客户端
	t := account.NewWaiterClient(conn)

	// 模拟请求数据
	username := "test123"
	password := "123456"

	// 调用gRPC接口
	tr, err := t.Login(context.Background(), &account.LoginReq{Username:username,Password:password})
	if err != nil {
		this.ErrorJson(666, err.Error())
	}
	//json转map
	res := common.JSONToMap(tr.BackJson)

	if (res["status"] == "666"){
		//登录成功
		this.SuccessJson(res["data"])
	}else{
		//登录失败
		this.ErrorJson(123, res["msg"].(string))
	}
}

总结

  RPC比起HTTP安全性更高,不必每次通信都要像HTTP一样去三次握手,减少了网络开销,所以,RPC性能消耗低,传输效率高,更适合公司内部的服务调用,缺点就是实现复杂。

  参考: 快速开始使用grpc(golang版)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!