目前微服務(wù)這么流行,RPC框架也是百花齊放,本文講述一下mac下grpc的開發(fā)環(huán)境搭建,其中server端使用golang,客戶端使用php。
服務(wù)端
golang grpc安裝
這里列出了一個(gè)參考,由于grpc在github上的文件目錄有改動(dòng),所以直接按官方的安裝,會(huì)出404資源無法找到的問題。
需要先在本地安裝golang+grpc。具體可參考:golang安裝grpc
操作完之后,在終端運(yùn)行:protoc --version,能看到版本信息
同時(shí),protoc-gen-go命令應(yīng)該也已經(jīng)被安裝

php grpc客戶端
擴(kuò)展有幾個(gè),推薦使用官方的。
當(dāng)然,另外一個(gè)也相當(dāng)不錯(cuò),datto的protobuf擴(kuò)展。使用datto的這個(gè)的時(shí)候,我用perl根據(jù)其文檔安裝失敗,既然官方的ok了,也就懶得再去折騰了。
官方的具體的安裝流程,剛剛給的github的網(wǎng)址上有詳細(xì)的說明,根據(jù)步驟走,就ok了。
安裝完之后,為了在nginx下使用,應(yīng)該裝grpc這個(gè)擴(kuò)展:

開始Demo
官方給了一個(gè)helloworld.proto的demo,咱們按樣子,增加一個(gè),目錄結(jié)構(gòu)如下:
app和meta,放的是protoc編譯之后的服務(wù)端的go的源碼。
grpc,將protoc編譯成PHP所需要的工具及源碼(即:grpc_php_plugin)
phpClient,是protoc編譯出來的php的源碼,下面的vendor文件夾是composer加載的grpc/grpc的php客戶端的連接服務(wù)端的源碼
上源碼
先建立文件夾:mkdir grpc_demo
meta.proto的源碼
syntax = "proto3";
package meta;
service Agent {
rpc GetInfo (MetaRequest) returns (MetaResponse);
}
message MetaRequest {
string appId = 1;
}
message MetaResponse {
string appId = 1;
string title = 2;
string name = 3;
string logo = 4;
}
編譯成golang文件:
protoc --go_out=plugins=grpc:./meta ./meta.proto
編譯成php文件:
protoc --proto_path=./ \
--php_out=phpClient/meta \
--grpc_out=phpClient/meta \
--plugin=protoc-gen-grpc=./grpc/bins/opt/grpc_php_plugin \
meta.proto
編寫main.go文件:(此處把helloworld.proto這個(gè)demo也加進(jìn)來了)
package main
import (
"log"
"net"
pb "grpc_demo/app"
meta "grpc_demo/meta"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
const (
port = ":50051"
)
// server is used to implement helloworld.GreeterServer.
type server struct{}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello " + in.Name + "--from jacky_chen"}, nil
}
func (s *server) GetInfo(ctx context.Context, in *meta.MetaRequest) (*meta.MetaResponse, error) {
return &meta.MetaResponse {
AppId: in.AppId,
Title: "my title",
Name: "My Name",
Logo: "https://xxx.com",
}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
meta.RegisterAgentServer(s, &server{})
s.Serve(lis)
}
agent_client.php源碼:
<?php
require dirname(__FILE__).'/../vendor/autoload.php';
print_r(get_declared_classes());exit;
include_once dirname(__FILE__).'/Meta/AgentClient.php';
include_once dirname(__FILE__).'/Meta/MetaRequest.php';
include_once dirname(__FILE__).'/Meta/MetaResponse.php';
include_once dirname(__FILE__).'/GPBMetadata/Meta.php';
$appId = "123";
try {
$client = new Meta\AgentClient('localhost:50051', [
'credentials' => Grpc\ChannelCredentials::createInsecure(),
]);
$request = new Meta\MetaRequest();
$request->setAppId($appId);
list($reply, $status) = $client->GetInfo($request)->wait();
echo $reply->serializeToJsonString();
} catch (\Throwable | \Error | \Exception $e) {
echo "error : " . $e->getMessage();
}
運(yùn)行服務(wù)端:
go run main.go
運(yùn)行客戶端:
php
結(jié)果如圖:

由于php本身的原因(官方是基于php-fpm,非常駐內(nèi)存),所以grpc官方并沒有php的服務(wù)端。當(dāng)然,基于swoole開發(fā)的grpc的服務(wù)端在github上已經(jīng)有了。