php+grpc+protobuf整合(php客戶端+go服務端)

PHP客戶端環境

本人使用爲debian系統下的docker容器安裝的php-fpm鏡像,php-fpm7.1.13鏡像承載系統爲alpine;

需要安裝工具

protoc: 將proto文件生成爲php文件的編譯器

grpc_php_plugin: protoc生成關於grpc的php文件的插件

grpc.so: php的grpc擴展

protobuf.so: php的protobuf擴展

debian系統安裝protoc

下載地址:https://github.com/protocolbuffers/protobuf/releases 選擇對應安裝版本下載之後解壓;

將解壓的後的 bin/protoc 文件添加到環境變量目錄裏;

通過命令:

root@iZ2zebyhcs68uwq5kc8ioxZ:~# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin

可以看到所有的環境變量目錄;

運行代碼:

[root@VM_179_192_centos ~]# protoc --version
libprotoc 3.6.1

表示成功;

debian系統安裝grpc_php_plugin插件

先創建個目錄存放將要git下來的grpc文件 例如:/app/grpcDemo

$ cd /app/
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc   grpcDemo
$ cd grpcDemo
$ git submodule update --init
$ make grpc_php_plugin

執行成功後會在grpc的bins/opt 目錄中看到grpc_php_plugin插件,在後面protoc生成grpc的php文件時會用到;

alpine系統內grpc.so安裝

使用pecl安裝即可,當然如果想要自己編譯,也可以

$ pecl install grpc

一般會缺少一些編譯工具,所以最好先安裝對應編譯工具

$ apk add --no-cache libstdc++
$ apk add --no-cache --update git make g++ unzip autoconf automake libtool file openssl curl

參考:https://github.com/c9s/alpine-grpc-dev/blob/master/edge/Dockerfile

安裝 grpc成功後,默認的grpc.so文件已放在對應目錄內,此時需要在php.ini內引入grpc.so擴展文件

$ vi /usr/local/etc/php/conf.d/docker-php-ext-grpc.ini

extension=grpc.so

alpine系統內protobuf.so安裝

同上和grpc.so類似安裝

$ pecl install protobuf

安裝 protobuf成功後,默認的protobuf.so文件已放在對應目錄內,此時需要在php.ini內引入protobuf.so擴展文件

$ vi /usr/local/etc/php/conf.d/docker-php-ext-protobuf.ini

extension=protobuf.so

注意:爲了能夠使用grpc擴展,還需要在項目裏composer安裝grpc文件才行,運行php項目需要使用此vendor

composer require grpc/grpc

PHP客戶端程序部署

protoc生成php文件

作爲demo的proto文件helloworld.proto

syntax = "proto3";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

只生成proto文件的話,不需要grpc_php_plugin插件,使用命令:

protoc --php_out=./ helloworld.proto

上面的方法只生成所有的proto對應的類,不生成實現grpc接口的stub client類。 使用下面的方法能同時生成stup client類

protoc --php_out=./ --grpc_out=./   --plugin=protoc-gen-grpc=/app/grpcDemo/bins/opt/grpc_php_plugin   helloworld.proto

php程序實現:thinkphp5.1.16語法

namespace app\proto\controller;
/**
 * Description of Demo
 * Date 2018年11月11日 13:22:05
 * @author Carter
*/
use Helloworld\GreeterClient;
use GPBMetadata\Helloworld;
use Helloworld\HelloRequest;
use Helloworld\HelloReply;
class Demo{
    //grpc客戶端實現
      public function greet()
      {
          debug('begin');
          $client = new GreeterClient('***.**.**.**:50051', ['credentials' => \Grpc\ChannelCredentials::createInsecure(),]);
          $request = new HelloRequest();
          $name = "world";
          $request->setName($name);
          list($reply, $status) = $client->SayHello($request)->wait();
          $message = $reply->getMessage();
          debug('end');
          echo "消耗時間:".debug('begin','end').'s'."\n";
          echo "消耗內存:".debug('begin','end','m')."\n";
          echo $message."\n";
      }
}

go服務端環境

本人使用服務器爲centos7.2,配合go1.9.2環境

需要安裝的工具

go環境安裝:1.9.2版本

grpc和protobuf資源包:相當於擴展

protoc: 將proto文件生成爲go文件的編譯器

go環境安裝

$ wget https://www.golangtc.com/static/go/1.9.2/go1.9.2.linux-amd64.tar.gz

解壓到某目錄,我這裏解壓到/usr/local/go目錄;

然後將此目錄添加爲環境變量目錄

設置環境變量
$ vim /etc/profile
添加
export GOROOT=/usr/local/go   //安裝目錄
export GOPATH=/app/goDemo    //項目目錄
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin   //項目執行文件目錄

保存
esc
:wq

創建項目目錄 /app/goDemo,以及附屬的子目錄 src,bin,pkg;

執行命令:

[root@VM_179_192_centos go]# go version
go version go1.9.2 linux/amd64

grpc和protobuf資源包

go get https://github.com/golang/protobuf
go get https://github.com/grpc/grpc-go

protoc安裝

go get -u github.com/golang/protobuf/proto
go get -u github.com/golang/protobuf/protoc-gen-go

編譯helloworld.proto文件生成對應go文件

protoc --go_out=plugins=grpc:. helloworld.proto

go服務端程序部署

在 /app/goDemo/src下新建greeter_server/main.go文件 代碼:

package main

import (
        "context"
        "log"
        "net"

        "google.golang.org/grpc"
        pb "helloworld"
        "google.golang.org/grpc/reflection"
)

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}, 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{})
        // Register reflection service on gRPC server.
        reflection.Register(s)
        if err := s.Serve(lis); err != nil {
                log.Fatalf("failed to serve: %v", err)
        }
}

注意:因爲翻牆原因,程序引入的一些包不會成功,所以需要自己從github查找到對應的資源,放在這些資源包裏;

例如:

go get https://github.com/grpc/grpc-go google.golang.org/grpc

然後就可以運行服務端程序了

go run main.go

對應的php客戶端開始訪問即可:

http://***.**.**.**/proto/demo/greet

返回結果:

消耗時間:0.051832s 消耗內存:12.79 KB Hello world

go客戶端環境測試

go客戶端代碼:使用http包測go客戶端也可以,使用程序測也可以,這裏使用啓動go客戶端啓動http服務後,測http請求

go客戶端代碼

新建 greeter_cient/main.go 文件

package main

import (
	"context"
	"log"
	"os"
	"time"
	"net/http"
	"google.golang.org/grpc"
	pb "helloworld"
)

const (
	address     = "localhost:50051"
	defaultName = "world"
)

func sayhelloName(w http.ResponseWriter,r *http.Request) {
	// Set up a connection to the server.
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	// Contact the server and print out its response.
	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("GreetingGreeting: %s", r.Message)
}

func main(){
	http.HandleFunc("/",sayhelloName)  //設置訪問的路由
	err := http.ListenAndServe(":9090",nil)   //設置監聽的端口
	if err != nil{
		log.Fatal("ListenAndServe:",err)
	}
}

啓動go客戶端http服務

$ go run main.go

HTTP請求go客戶端

http://**.**.**.**:9090/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章