Grpc之golang服务端与laravel客户端

1,050 阅读3分钟

#1 安装 protobuf

  • 1.How to Install Latest Protobuf on Ubuntu 18.04
sudo apt-get install autoconf automake libtool curl make g++ unzip -y
git clone https://github.com/google/protobuf.git
cd protobuf
git submodule update --init --recursive
./autogen.sh
./configure
make
make check
sudo make install
sudo ldconfig
#1 下载 https://github.com/protocolbuffers/protobuf/releases
mkdir temp
cd temp
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.17.3/protobuf-all-3.17.3.tar.gz
tar -zxvf protobuf-all-3.17.3.tar.gz
cd protobuf-all-3.17.3
./configure
make
make check
sudo make install
sudo ldconfig # refresh shared library cache.

#2 安装 protobuf golang 插件

vagrant@homestead:/var/gin-vue/top/server$ go mod tidy
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

#3 go版本gRpc服务端和客户端demo

#1 proto文件编写以及自动生成go代码

// 在pb/ctrip/hotel 新建文件 ct_sub_hotel.proto
syntax = "proto3";

package hotel;
option go_package = "./";

// 定义服务
service SubHotel {
    rpc CreateSubHotel(SubHotelRequest) returns (SubHotelReplay) {}
}

// 请求体的结构体
message SubHotelRequest {
    int64 hotelId = 1;
}

// 响应的结构体
message SubHotelReplay {
    string message = 1;
    int64 code = 2;
}

# 在pb/ctrip/hotel 目录中输入命令
# 如果报错`protoc-gen-go: unable to determine Go import path for "ct_sub_hotel.proto"`
# 需要在上面文件中加入  option go_package = "./";
vagrant@homestead:/var/gin-vue/top/server/pb/ctrip/hotel$ protoc --go_out=plugins=grpc:. ct_sub_hotel.proto

## 或者在上面文件中加入  option go_package = "ctrip/hotel";
vagrant@homestead:/var/gin-vue/top/server/pb$ protoc --go_out=plugins=grpc:. ctrip/hotel/*.proto

## 
vagrant@homestead:/var/gin-vue/top/server/pb$ protoc --go_out=. --go_opt=paths=source_relative \
    --go-grpc_out=. --go-grpc_opt=paths=source_relative \
    ctrip/hotel/*.proto

#2 服务器端代码

server/debug/gRpc/server/main.go

package main

import (
	"context"
	"fmt"
	pb "gin-vue-admin/pb/ctrip/hotel"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
	"log"
	"net"
)

type server struct {}

// 实现SubHotelServer接口
func (s *server) CreateSubHotel(ctx context.Context, in *pb.SubHotelRequest) (*pb.SubHotelReplay, error) {
	return &pb.SubHotelReplay{Message: fmt.Sprintf("需要新增的子酒店ID:%d", in.HotelId), Code: 200}, nil
}

func main() {
	lis, err := net.Listen("tcp", ":50051")

	if err != nil {
		log.Fatalf("failed to listen: %v\n", err)
	}

	s := grpc.NewServer()
	pb.RegisterSubHotelServer(s, &server{})

	// 在 server 中 注册 gRPC 的 reflection service
	reflection.Register(s)
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to server: %v\n", err)
	}
}

#3 gin客户端代码

package main

import (
	"fmt"
	pb "gin-vue-admin/pb/ctrip/hotel"
	"github.com/gin-gonic/gin"
	"google.golang.org/grpc"
	"log"
	"net/http"
	"strconv"
)

func main() {
	r := gin.Default()

	r.GET("/rpc/ctrip/hotel/create-sub-hotel", func(c *gin.Context) {
		createSubHotel(c)
	})

	// Run http server
	if err := r.Run(":8052"); err != nil {
		log.Fatalf("could not run server: %v", err)
	}
}

func createSubHotel(c *gin.Context) {
	conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Connection err:%v\n", err)
	}

	defer conn.Close()

	client := pb.NewSubHotelClient(conn)
	hotelId, _ := strconv.ParseInt(c.DefaultQuery("hotelId", "17555"), 10, 64)
	req := &pb.SubHotelRequest{
		HotelId: hotelId,
	}
	res, err := client.CreateSubHotel(c, req)

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"result": fmt.Sprint(res.Message),
		"code": fmt.Sprint(res.Code),
	})

}

#4 测试

# bash1
vagrant@homestead:/var/gin-vue/top/server/debug/gRpc/server$ go run main.go

# bash2
vagrant@homestead:/var/gin-vue/top/server/debug/gRpc/client$ go run main.go

# chrom访问接口地址
# http://192.168.10.10:8052/rpc/ctrip/hotel/create-sub-hotel?hotelId=17587
#{
#    "code": "200",
#    "result": "需要新增的子酒店ID:17587"
#}

#4 php-gRpc客户端

#1 安装过程

## 解决错误 php7.2-dev : Depends: libssl-dev but it is not going to be installed
sudo apt list | grep php | grep dev
sudo apt-get update
#sudo apt-get install php-common
#依据sudo apt-get install libssl-dev的报错信息安装
#libssl-dev : Depends: libssl1.1 (= 1.1.1-1ubuntu2.1~18.04.9) but 1.1.1d-1+ubuntu18.04.1+deb.sury.org+2 is to be installed
sudo apt-get install libssl1.1=1.1.1-1ubuntu2.1~18.04.9
sudo apt-get install libssl-dev
sudo apt-get install php7.2-dev
# 看是否安装成功
phpize -v
# 安装php-gRpc
sudo pecl install grpc
# 安装php-protobuf
sudo pecl install protobuf
# 如果遇到错误 fatal error: zlib.h: No such file or directory
sudo apt-get install zlib1g-dev
## php.ini地址/etc/php/7.2/fpm/pool.d/www.conf
cd /etc/php/7.2
sudo vim mods-available/grpc.ini
####写入以下信息
extension=grpc.so
####

sudo vim mods-available/protobuf.ini
####写入以下信息
extension=protobuf.so
####

# 写入软链接
sudo ln -s /etc/php/7.2/mods-available/grpc.ini cli/conf.d/20-grpc.ini
sudo ln -s /etc/php/7.2/mods-available/grpc.ini fpm/conf.d/20-grpc.ini

sudo ln -s /etc/php/7.2/mods-available/protobuf.ini cli/conf.d/20-protobuf.ini
sudo ln -s /etc/php/7.2/mods-available/protobuf.ini fpm/conf.d/20-protobuf.ini
# 验证
php -m | grep grpc
php -m | grep protobuf
# fpm重启
sudo service php7.2-fpm restart
sudo service nginx restart

#2 自行编译方式安装

# php-gRpc pecl地址:https://pecl.php.net/package/gRPC
wget https://pecl.php.net/get/grpc-1.38.0.tgz
tar -zxvf grpc-1.38.0.tgz
/usr/bin/phpize #(这个根据`phpize`实际情况来)
./configure --with-php-config=/usr/bin/php-config #(这个根据`php-config`实际情况来)
make && make install
vim /etc/php/7.2/mods-available/grpc.ini #这个根据实际情况去决定 是改`php.ini`还是别的什么
写入 extension=grpc.so
如果没有将grpc.so写入到lib中则自行拷贝
vagrant@homestead:~/temp/grpc-1.38.0$sudo cp modules/grpc.so /usr/lib/php/20170718/grpc.so

#3 安装protoc-gen-php 扩展

$ git clone --recurse-submodules -b v1.38.0 https://github.com/grpc/grpc

## 国内环境经常会卡在 --recurse-submodules 如果克隆完成,子模块更新失败则cd进入后
$ git submodule update --init

$ cd grpc
$ mkdir -p cmake/build
$ pushd cmake/build
$ cmake ../..
$ make protoc grpc_php_plugin
$ popd

#4 生成php版客户端代码

~/temp/grpc/cmake/build$ sudo cp grpc_php_plugin /usr/local/bin/
~/code/top/pb$ protoc --php_out=./ --grpc_out=./ --plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin ct_sub_hotel.proto

##
~/code/top$ protoc --php_out=./app/Libs/Grpc --grpc_out=./app/Libs/Grpc --plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin ./app/Libs/Grpc/proto/hotel.proto

如果报app/Libs/Grpc/proto/hotel.proto:9:1: Import "google/api/annotations.proto" was not found or had errors.错误,需要去https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto下载相关的proto文件,放在与app文件夹平行的地方

image.png

#5 添加composer相关依赖

composer require google/protobuf
composer require grpc/grpc
composer require google/common-protos

image.png

#6 php代码


use Pb\Ctrip\Hotel\Ct_sub_hotel\Proto\SubHotelClient;
use Pb\Ctrip\Hotel\Ct_sub_hotel\Proto\SubHotelRequest;

class GrpcController extends BaseController
{
    private function gRpc(Request $request)
    {
        $client = new SubHotelClient("127.0.0.1:50051", [
            'credentials' => \Grpc\ChannelCredentials::createInsecure(),
        ]);
        $subHotelRequest = new SubHotelRequest();
        $subHotelRequest->setHotelId($request->get("hotelId", 999));
        $call = $client->CreateSubHotel($subHotelRequest);
        [$reply, $status] = $call->wait();

        $message = $reply->getMessage();
        $code = $reply->getCode();
        return [
            'message' => $message,
            'code' => $code,
        ];
    }
}
  • 输出结果
{
    "message": "需要新增的子酒店ID:16056",
    "code": 200
}

#7 参考资料

#4 安装 Buf

#1 安装brew

## https://brew.sh/index_zh-cn
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

#2 安装Buf

## https://docs.buf.build/installation#from-source
GO111MODULE=on GOBIN=/usr/local/bin go install \
github.com/bufbuild/buf/cmd/buf \
github.com/bufbuild/buf/cmd/protoc-gen-buf-breaking \
github.com/bufbuild/buf/cmd/protoc-gen-buf-lint

#5 日常一键生成命令

#1 生成proto和service命令

## 安装Kratos
go install github.com/go-kratos/kratos/cmd/kratos/v2@latest 
kratos upgrade
# 2 通过Kratos生成proto 
kratos proto add api/proto/sp/meituan/v1/hotel_room_status.proto
# 3 通过Kratos生成service
kratos proto server api/proto/sp/meituan/v1/hotel_room_status.proto -t grpc/internal/service/sp

#2 buf生成go-gRpc代码

  • buf.yaml
version: v1beta1
name: buf.build/gin-vue-admin/top
deps:
  - buf.build/beta/googleapis
build:
  roots:
    - api/proto/ota/ctrip/v1
  • buf.gen.yaml
version: v1beta1
plugins:
  - name: go
    #out: api/proto/ota/ctrip/v1
    out: api/proto/sp/meituan/v1
    opt: paths=source_relative
  - name: go-grpc
    #out: api/proto/ota/ctrip/v1
    out: api/proto/sp/meituan/v1
    opt: paths=source_relative,require_unimplemented_servers=false
  - name: grpc-gateway
    #out: api/proto/ota/ctrip/v1
    out: api/proto/sp/meituan/v1
    opt: paths=source_relative
# https://grpc-ecosystem.github.io/grpc-gateway/docs/tutorials/adding_annotations/
# https://docs.buf.build/installation/#from-source
buf beta mod update
buf generate