install go lang
$ wget https://storage.googleapis.com/golang/go1.2.5.linux-amd64.tar.gz
$ tar vzfx go1.12.5.linux-amd64.tar.gz
$ sudo mv go /usr/local/
$ export PATH=$PATH:/usr/local/go/bin
$ export GOPATH=$HOME/go
$ go version
test
$ mkdir go/src/hello
$ cd go/src/hello
$ touch hello.go
package main
import "fmt"
func main() {
fmt.Printf("hello, world\n")
}
$ go build
$ go run hello
gRPC
hoge.proto
記述 | 記述ルール | 説明 |
---|---|---|
ファイル名 | スネークケース | メッセージとサービスを定義するファイル |
メッセージ名 | アッパーキャメルケース | サーバーとクライアント間でやりとりするデータ |
フィールド名 | スネークケース | データのフィールド名 |
サービス名 | アッパーキャメルケース | サーバーとクライアント間で通信するサービス名を定義する。リクエストとレスポンスのメッセージも記述。 |
hoge_client/main.go
プロトコルファイルで定義したサービスやメッセージを使用してクライアントサイドサービスの振舞いを実装する。
記述 | 記述ルール | 説明 |
---|---|---|
サービス名 | アッパーキャメルケース | 振舞いを記述 |
メッセージフィールド | アッパーキャメルケース | データのフィールド名 |
hoge_server/main.go
プロトコルファイルで定義したサービスやメッセージを使用してサーバーサイドサービスの振舞いを実装する。
記述 | 記述ルール | 説明 |
---|---|---|
サービス名 | アッパーキャメルケース | 振舞いを記述 |
メッセージフィールド | アッパーキャメルケース | データのフィールド名 |
install gRPC
$ go get -u google.golang.org/grpc
Install Protocol Buffers v3
$ go get -u github.com/golang/protobuf/protoc-gen-go
$ export PATH=$PATH:$GOPATH/bin
examples
公式ドキュメント
Go言語に変換(対応言語のProtocol Buffersへ変換)
$ protoc -I helloworld/ helloworld/helloworld.proto --go_out=plugins=grpc:helloworld
※-bash: protoc: command not foundの場合
$ yum install zip
$ yum install unzip
$ PROTOC_ZIP=protoc-3.7.1-linux-x86_64.zip
$ curl -OL https://github.com/google/protobuf/releases/download/v3.7.1/$PROTOC_ZIP
$ sudo unzip -o $PROTOC_ZIP -d /usr/local bin/protoc
$ rm -f $PROTOC_ZIP
注意
proto、server、clientの順にコードを修正する。
お試し
helloworldを参考にさわってみる。
パッケージの準備
src/
├ user/
│ └ user/
│ └ user.proto
├ user_client/
│ └ get_user.go
│ └ create_user.go
├ user_server/
│ └ main.go
└ mock_user/
protoファイル編集
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.user";
option java_outer_classname = "UserProto";
package user;
// User service definition.
service User {
// send user_id
rpc GetUser (RequestUserId) returns (UserResponse) {}
// create user
rpc CreateUser (CreateUserRequest) returns (UserResponse) {}
}
// The request message containing the user's name.
message RequestUserId {
string user_id = 1;
}
message CreateUserRequest {
string name = 1;
string mail = 2;
BloodType blood_type = 3;
int32 age = 4;
}
message UserResponse {
string id = 1;
string name = 2;
string mail = 3;
BloodType blood_type = 4;
int32 age = 5;
}
enum BloodType {
A = 0;
B = 1;
O = 2;
AB = 4;
}
Go言語へコンパイル
$ protoc -I user/ user/user.proto --go_out=plugins=grpc:user
serverファイル編集
//go:generate protoc -I ../users --go_out=plugins=grpc:../user ../user/user.proto
// Package main implements a server for User service.
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "../user"
)
const (
port = ":50051"
)
// server is used to implement Users.UsersServer.
type server struct{}
// GetUser implements User.UserServer
func (s *server) GetUser(ctx context.Context, user *pb.RequestUserId) (*pb.UserResponse, error) {
log.Printf("Received: %v", user.UserId)
return &pb.UserResponse{
Id: user.UserId,
Name:"Tom",
Mail:"hoge@fuga.com",
BloodType:0,
Age:25}, nil
}
// CreateUser implements User.UserServer
func (s *server) CreateUser(ctx context.Context, m *pb.CreateUserRequest) (*pb.UserResponse, error) {
return &pb.UserResponse{
Id: "1",
Name:m.Name,
Mail:m.Mail,
BloodType:m.BloodType,
Age:m.Age}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterUserServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
clientファイル編集
// Package main implements a client for User service.
package main
import (
"context"
"log"
"os"
"time"
"google.golang.org/grpc"
pb "../user"
)
const (
address = "localhost:50051"
defaultUserId = "1"
)
func main() {
// 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.NewUserClient(conn)
// Contact the server and print out its response.
userId := defaultUserId
if len(os.Args) > 1 {
userId = os.Args[1]
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.GetUser(ctx, &pb.RequestUserId{UserId: userId})
if err != nil {
log.Fatalf("get user error: %v", err)
}
log.Printf("User Name: %s", r.Name)
}
// Package main implements a client for User service.
package main
import (
"context"
"log"
"time"
"flag"
"google.golang.org/grpc"
pb "../user"
)
const (
address = "localhost:50051"
)
func main() {
// 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.NewUserClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
var (
cName = flag.String("name", "test", "name")
cMail = flag.String("mail", "test@example.com", "mail")
cAge = flag.Int("age", 20, "age")
)
flag.Parse()
r, err := c.CreateUser(ctx, &pb.CreateUserRequest{Name: *cName, Mail: *cMail, BloodType:0, Age:int32(*cAge)})
if err != nil {
log.Fatalf("could not create user: %v", err)
}
log.Printf("Create User: {Id: %s, Name:%s, Mail:%s, BloodType:%s, Age:%s}", r.Id, r.Name, r.Mail, r.BloodType, r.Age)
}
gRPC server start
# 環境変数の登録してなかった場合は環境変数を設定
$ export PATH=$PATH:/usr/local/go/bin
$ export GOPATH=$HOME/go
$ export PATH=$PATH:$GOPATH/bin
$ go run users_server/main.go
gRPC client通信
# 環境変数の登録してなかった場合は環境変数を設定
$ export PATH=$PATH:/usr/local/go/bin
$ export GOPATH=$HOME/go
$ export PATH=$PATH:$GOPATH/bin
$ go run users_client/get_user.go
2019/05/22 06:10:50 User Name: Tom
$ go run user_client/create_user.go -name Thomas -mail test -age 25
2019/05/22 06:10:04 Create User: {Id: 1, Name:Thomas, Mail:test, BloodType:A, Age:%!s(int32=25)}