php+golang grpc客户端和服务端详细案例

测试环境:win10、centos7.9、php7.4、golang1.17

一、安装 protobuf

  • 1、protoc的源码和各个系统的预编译包 - https://github.com/protocolbuffers/protobuf/releases

  • 2、选择对应的安装文件下载,解压(tips:文件解压的路径最好是英文,无任何特殊字符,包括空格;之前安装es插件时就因为Program
    Files中有个空格,导致安装失败)

php+golang grpc客户端和服务端详细案例_第1张图片

  • 3、添加到环境变量中(win10)
    步骤:电脑 -> 右键 -> 属性 -> 高级系统设置 -> 环境变量 -> 系统变量 -> 选中 [ Path ] -> 编辑 -> 新建 [ copy:D:\ProgramFiles\protoc-3.13.0-win64\bin ] -> 依次确定关闭弹框

php+golang grpc客户端和服务端详细案例_第2张图片

  • 4、查看是否成功安装,查看对应的版本即可
protoc --version    #查看protoc的版本

版本信息打印如下:

libprotoc 3.13.0

二、安装PHP相关扩展(grpc、protobuf)

#安装PECL
wget http://pear.php.net/go-pear.phar
php go-pear.phar

#php版本 < 7
yum install php-pear

#安装grpc、protobuf扩展
pecl install protobuf
pecl install grpc
  • 如果grpc安装不上报错可能是cmake版本原因

方法1,升级camke版本
参考:https://blog.csdn.net/CrystalShaw/article/details/120043042

方法2,降低grpc版本

#可以到pecl选一个版本,http://pecl.php.net/package/gRPC
#如:
pecl install grpc-1.31.1

安装成功后,需要将生成的grpc.so和protobuf.so文件移动到php扩展目录下,并加载到php.ini中,如:

#扩展路径请改为你实际的路径
extension = /www/server/php/74/lib/php/extensions/no-debug-non-zts-20190902/protobuf.so

extension = /www/server/php/74/lib/php/extensions/no-debug-non-zts-20190902/grpc.so
  • 生成grpc_php_plugin
git clone  https://github.com/grpc/grpc
cd grpc
git submodule update --init
mkdir -p cmake/build
cd cmake/build
cmake ../..
make protoc grpc_php_plugin
mv ./grpc_php_plugin /opt/homebrew/bin/

如果是国内服务器,一直安装不成功,其原因众所周知无非就是有些东西需要科学上网
找到项目的.gitmodules文件,这个文件就是子工程的clone path 以及clone的位置:
php+golang grpc客户端和服务端详细案例_第3张图片
我们只需要找到url对应的可访问地址,这里给出两个结局的方案,也是我常用的方案:

1、使用github镜像地址:http://git.what996.com
2、在gitee上找别人fork好的对应项目的地址
这里我们使用第一种,将url的https://github.com换成http://git.what996.com

然后在执行git submodule update --init就ok了

三、生成proto文件和grpc代码

  • 创建文件:hello.proto,内容如下:
syntax = "proto3";
package services;
option go_package = "./;proto";
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
  string name = 1;
}
message HelloReply {
  string message = 1;
  int64 len = 2;
}
  • 生成go语言文件:
#在hello.proto文件目录下执行
protoc -I. --go_out=plugins=grpc:./ ./*.proto

执行成功后会生成一个hello.pb.go文件
在这里插入图片描述

hello.pb.go的包名为proto,后续写服务端和客户端代码需要引入此文件
php+golang grpc客户端和服务端详细案例_第4张图片

  • 编写go服务端代码,server.go:
package main

import (
	"context"
	"fmt"
	"proto" #引入生成的go文件,路径改成你实际的引入路径
	"google.golang.org/grpc"
	"net"
)

// 服务端
var Server = new(server)

type server struct{}

// 业务逻辑
func (s *server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
	res := &proto.HelloReply{
		Message: "hello " + request.Name,
		Len:     101,
	}

	fmt.Print("SayHello成功调用..\r\n")
	return res, nil
}

// 启动rpc的server服务
func (s *server) Start() {
	// 1.实例化server
	g := grpc.NewServer()
	// 2.注册逻辑到server中
	proto.RegisterGreeterServer(g, &server{})
	// 3.启动server
	lis, err := net.Listen("tcp", ":8399")
	if err != nil {
		panic("监听错误:" + err.Error())
	}

	fmt.Print("grpc启动服务成功..\r\n")

	err = g.Serve(lis)
	fmt.Print("err:", err)
	if err != nil {
		panic("grpc服务端运行错误:" + err.Error())
	}

}

func main() {
	Server.Start()
}
  • 编写go客户端代码,client.go:
package main

import (
	"context"
	"fmt"
	"proto" #引入生成的go文件,路径改成你实际的引入路径
	"google.golang.org/grpc"
)

// rpc调用
func clientRpc(body map[string]string) (res *proto.HelloReply, err error) {
	name := body["name"]
	conn, err := grpc.Dial("localhost:8399", grpc.WithInsecure())
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	rpc := proto.NewGreeterClient(conn)
	response, err := rpc.SayHello(context.Background(), &proto.HelloRequest{Name: name})
	if err != nil {
		return nil, err
	}
	return response, nil
}

// 业务代码
func start() {
	body := make(map[string]string)
	body["name"] = "niubi!"
	response, err := clientRpc(body)
	if err != nil {
		fmt.Println("rpc调用失败:", err)
		return
	}
	fmt.Println(response.Message)
}
func main() {
	start()
}
  • 生成php语言文件:
#在hello.proto文件目录下执行
protoc --proto_path=./ --php_out=.. --grpc_out=.. --plugin=protoc-gen-grpc=(这里改成你实际生成grpc_php_plugin的路径) ./*.proto

执行成功后会生成以下几个文件:
php+golang grpc客户端和服务端详细案例_第5张图片

  • 编写php客户端代码,client.php:
<?php

require dirname(__FILE__) . '/vendor/autoload.php';

$hostname = 'localhost:8399';

$client       = new \Services\GreeterClient(
    $hostname, [
    'credentials' => Grpc\ChannelCredentials::createInsecure(),
]
);
$indexRequest = new \Services\HelloRequest();
$indexRequest->setName($name = '测试');
/**
 * @var \Services\HelloReply $response
 */
[$response, $status] = $client->SayHello($indexRequest)->wait();

if ($status->code !== Grpc\STATUS_OK) {
    echo "ERROR: " . $status->code . ", " . $status->details . PHP_EOL;
}

var_export($response->serializeToJsonString());
  • 如果你是第一次使用,还需要配置composer:
#安装grpc扩展包
composer require google/protobuf
composer require grpc/grpc

#将生成的php类文件加载到composer ,注意路径改成你实际的路径
    "autoload":{
        "psr-4":{
            "GPBMetadata\\":"common/grpc/GPBMetadata/",
            "Services\\":"common/grpc/Services/"
        }
    }

# 更新composer配置    
composer update    
  • 启动GRPC服务
#go服务端:
go run server.go 

#go客户端:
go run client.go 

#php客户端:
php  client.php
  • go服务端测试:
    php+golang grpc客户端和服务端详细案例_第6张图片

  • go客户端测试:
    在这里插入图片描述

  • php客户端测试:
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/349c2e2cf1424d4980dbed5d449ba942.png

至此,php+golang grpc客户端和服务端详细案例结束!

你可能感兴趣的:(php,go,golang,php)