一. 环境准备。
- 安装
gprc
。
go get -u google.golang.org/grpc
- 安装
protocol buffers
。
下载地址: https://github.com/protocolbuffers/protobuf/releases
下载解压后放入PATH路径下
二. 实现服务端。
- 新建
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;
}
- 生成golang的服务代码
protoc --go_out=plugins=grpc:. ./account.proto
- 实现服务端接口
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
}
- 服务端的
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性能消耗低,传输效率高,更适合公司内部的服务调用,缺点就是实现复杂。
来源:oschina
链接:https://my.oschina.net/u/4315748/blog/4451287