grpcgolanghttpswofthyperf
gin 实现 grpc 简单的应答
安装protobuf
1、安装相关软件 ,我用的是 contOS7+windows , mac应该更好装一点
yum install autoconf automake libtool gcc gcc-c++ zlib-devel
2、 下载protobuf,并安装
去到 Protocol Buffers 下载最新版本,然后解压到本地。
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.10.1/protoc-3.10.1-linux-x86_64.zip
unzip protoc-3.10.1-linux-x86_64.zip
protoc --version # 能看到 版本信息就安装成功了
安装 protobuf golang 插件
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
前提条件
export GOPROXY=https://goproxy.cn
export GO111MODULE=on - rpc-hello
- pb
- hello.proto
- go.mod syntax = "proto3";
package hello;
// 定义服务
service Hello {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// 请求体的结构体
message HelloRequest {
string name = 1;
}
// 响应的结构体
message HelloReply {
string message = 1;
int64 code = 2;
}
protoc --go_out=plugins=grpc:. hello.proto
rpc-hello\pb\hello.pb.go
grpc四种服务类型:
1、简单方式:这就是一般的rpc调用,一个请求对象对应一个返回对象
2、服务端流式(Sever-side streaming )
3、客户端流式(Client-side streaming RPC)
4、双向流式(Bidirectional streaming RPC)
简单方式的调用
rpc-hello
- pb
- hello.proto
- hello.pb.go
- go.mod
- service
- service.go
- client
- client.go
package main
import (
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"log"
"net"
pb "rpc-hello/pb"
)
// server 用来实现 hello.HelloServer
type server struct{}
// 实现 hello.SayHello 方法
// (context.Context, *HelloRequest) (*HelloReply, error)
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello " + in.Name, Code: 200}, nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterHelloServer(s, &server{})
//在 server 中 注册 gRPC 的 reflection service
reflection.Register(s)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"google.golang.org/grpc"
"log"
"net/http"
pb "rpc-hello/pb"
)
func main() {
r := gin.Default()
r.GET("/rpc/hello", func(c *gin.Context) {
sayHello(c)
})
// Run http server
if err := r.Run(":8052"); err != nil {
log.Fatalf("could not run server: %v", err)
}
}
func sayHello(c *gin.Context) {
// Set up a connection to the server.
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
client := pb.NewHelloClient(conn)
name := c.DefaultQuery("name","战士上战场")
req := &pb.HelloRequest{Name: name}
res, err := client.SayHello(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),
})
}
php 原生实现客户端
安装 protoc-gen-php 扩展
git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
cd grpc
git submodule update --init # 这一步 要下4个小时,建议还是要挂git代理
make grpc_php_plugin # 警告没事,没error 就行
# 建议 国内用户换这个 ,再切换到对应版本分支,不然太难受了
git clone https://gitee.com/devin2019/grpc.git
cd grpc
git checkout xxxx # 对应分支
git submodule update --init #这一步 要下4个小时,建议还是要挂git代理
make grpc_php_plugin # 警告没事,没error 就行
grpc_php_plugin/pathto/grpc/bins/opt/grpc_php_plugin
安装 grpc 扩展
wget https://pecl.php.net/get/grpc-1.25.0.tgz
tar -zxvf grpc-1.25.0.tgz
/usr/bin/phpize #(这个根据`phpize`实际情况来)
./configure --with-php-config=/usr/bin/php-config #(这个根据`php-config`实际情况来)
make && make install
vim /etc/php.d/grpc.ini #这个根据实际情况去决定 是改`php.ini`还是别的什么
写入 extension=grpc.so
安装 protobuf 扩展
wget https://pecl.php.net/get/protobuf-3.10.0.tgz
tar -zxvf protobuf-3.10.0.tgz
/usr/bin/phpize #(这个根据`phpize`实际情况来)
./configure --with-php-config=/usr/bin/php-config #(这个根据`php-config`实际情况来)
make && make install
vim /etc/php.d/protobuf.ini #这个根据实际情况去决定 是改`php.ini`还是别的什么
写入 extension=protobuf.so "require": {
"google/protobuf": "^v3.10.0"
},
生成文件 带客户端
|-- composer.json
|-- composer.lock
|-- GPBMetadata
| |-- Hello.php
|-- Hello
| |-- HelloClient.php
| |-- HelloReply.php
| |-- HelloRequest.php
|-- hello.proto
|-- index.php
|-- vendor
index.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use \Grpc\ChannelCredentials;
use \Hello\HelloClient;
use \Hello\HelloRequest;
use \Hello\HelloReply;
// 创建客户端实例
$helloClient = new HelloClient('127.0.0.1:50051', [
'credentials' => ChannelCredentials::createInsecure()
]);
$helloRequest = new HelloRequest();
$helloRequest->setName("有事别找我");
$request = $helloClient->SayHello($helloRequest)->wait();
//返回数组
/** @var array $status */
/** @var HelloReply $response */
list($response, $status) = $request;
var_dump($response->getMessage());
echo PHP_EOL;
var_dump($status);
composer.json
{
"name": "rpc/test",
"require": {
"grpc/grpc": "v1.25.0",
"google/protobuf": "^v3.10.0"
},
"autoload":{
"psr-4":{
"GPBMetadata\\":"GPBMetadata/",
"Hello\\":"Hello/"
}
},
"repositories": {
"packagist": {
"type": "composer",
"url": "https://mirrors.aliyun.com/composer/"
}
}
}
composer dump -oservice.gophp index.php
php swoolehyperfgolang
swooleswoole2.xhyperfphp.iniswoole.use_shortname=offcomposer create-project hyperf/hyperf-skeletongrpc
服务端
|-- GPBMetadata
| |-- Hello.php
|-- Hello
| |-- HelloClient.php
| |-- HelloReply.php
| |-- HelloRequest.php "GPBMetadata\\": "grpc/GPBMetadata",
"Grpc\\": "grpc/Grpc" [
'name' => 'grpc',
'type' => Server::SERVER_HTTP,
'host' => '0.0.0.0',
'port' => 50051,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
SwooleEvent::ON_REQUEST => [\Hyperf\GrpcServer\Server::class, 'onRequest'
],
],
], Router::addServer("grpc", function () {
Router::addGroup('/hello.Hello', function () {
Router::post('/SayHello', 'App\Controller\IndexController@sayHello');
});
}); public function sayHello(HelloRequest $request)
{
$message = new HelloReply();
$message->setMessage("Hello {$request->getName()}");
$message->setCode(200);
return $message;
}
客户端
use Hello\HelloClient;
use Hello\HelloReply;
use Hello\HelloRequest;
use Hyperf\HttpServer\Contract\RequestInterface;
public function index(RequestInterface $request)
{
$client = new HelloClient("127.0.0.1:50051", ['credentials' => null]);
$name = $request->input("name","战士上战场");
$helloRequest = new HelloRequest();
$helloRequest->setName($name);
/**
* @var HelloReply $reply
*/
list($reply, $status) = $client->sayHello($helloRequest);
$message = $reply->getMessage();
$code = $reply->getCode();
$client->close();
var_dump(memory_get_usage(true));
return [
'message' => $message,
'code' => $code,
];
}
namespace Hello;
use Hyperf\GrpcClient\BaseClient;
/**
* 定义服务
*/
class HelloClient extends BaseClient{
public function sayHello(HelloRequest $argument)
{
return $this->simpleRequest(
'/hello.Hello/SayHello',
$argument,
[HelloReply::class, 'decode']
);
}
} namespace Hello;
/**
* 定义服务
*/
class HelloClient extends \Grpc\BaseStub {
/**
* @param string $hostname hostname
* @param array $opts channel options
* @param \Grpc\Channel $channel (optional) re-use channel object
*/
public function __construct($hostname, $opts, $channel = null) {
parent::__construct($hostname, $opts, $channel);
}
/**
* @param \Hello\HelloRequest $argument input argument
* @param array $metadata metadata
* @param array $options call options
*/
public function SayHello(\Hello\HelloRequest $argument,
$metadata = [], $options = []) {
return $this->_simpleRequest(
'/hello.Hello/SayHello',
$argument,
['\Hello\HelloReply', 'decode'],
$metadata, $options);
}
}
本作品采用《CC 协议》,转载必须注明作者和本文链接