## 内容
gRPCをGo言語で使用する基本的な例を提供します。
この例では、簡単なgRPCサービスを定義し、そのサービスを実装したサーバーとクライアントを作成します。
### Step 1: Protocol Buffers (protobuf) の定義
まず、`.proto` ファイルを作成して、gRPCサービスとメッセージ形式を定義します。`helloworld.proto` という名前のファイルを作成し、以下の内容を記述します。
```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;
}
```
### Step 2: gRPCコードの生成
上記の`.proto`ファイルから、Goのソースコードを生成する必要があります。これには、`protoc`コンパイラとGo用のgRPCプラグインが必要です。
```sh
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
helloworld.proto
```
このコマンドを実行すると、`helloworld.pb.go` と `helloworld_grpc.pb.go` という2つのファイルが生成され、これらには定義したサービスに必要なGoのコードが含まれます。
### Step 3: gRPCサーバーの実装
次に、gRPCサーバーを実装します。`server.go`という名前のファイルを作成し、以下のコードを記述します。
```go
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "path/to/your/helloworld" // 実際のパスに置き換えてください
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
```
### Step 4: gRPCクライアントの実装
最後に、サーバーに接続してメソッドを呼び出すクライアントを実装します。`client.go`という名前のファイルを作成し、以下のコードを記述します。
```go
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
pb "path/to/your/helloworld" // 実際のパスに置き換えてください
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
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.
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "world"})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %v", r.GetMessage())
}
```
### 実行方法
1. まず、サーバーを起動します。
```sh
go run server.go
```
2. 次に、別のターミナルウィンドウでクライアントを起動します。
```sh
go run client.go
```
これで、クライアントがサーバーに "Hello world" というメッセージを送信し、サーバーからの応答を受け取る基本的なgRPC通信が実装できました。
`server.go` と `client.go` は、`helloworld.pb.go` と `helloworld_grpc.pb.go` によって生成されたコードに基づいて書かれます。これらの生成されたファイルには、protobuf定義から派生したGoの型と、gRPCのサーバーとクライアントのインターフェースが含まれています。以下は、このプロセスを理解するための概要です。
### `helloworld.pb.go` と `helloworld_grpc.pb.go` の役割
- **`helloworld.pb.go`**:
- `.proto` ファイルで定義されたメッセージ型(この例では `HelloRequest` と `HelloReply`)をGoの型として提供します。
- protobufメッセージをシリアライズ(エンコード)およびデシリアライズ(デコード)するための関数も含まれています。
- **`helloworld_grpc.pb.go`**:
- `.proto` ファイルで定義されたサービス(この例では `Greeter` サービス)のためのgRPCのクライアントとサーバーのインターフェースを提供します。
- サーバーサイドでは、実装すべきメソッド(この例では `SayHello`)のスタブが含まれています。
- クライアントサイドでは、サーバーのメソッドをリモートで呼び出すためのメソッドが含まれています。
### 実装の流れ
1. **サーバー実装 (`server.go`)**:
- `helloworld_grpc.pb.go` に定義された `GreeterServer` インターフェースを実装することにより、サービスロジックを定義します。
- このインターフェースには、`SayHello` メソッドが含まれており、具体的なビジネスロジックを実装する必要があります。
2. **クライアント実装 (`client.go`)**:
- `helloworld_grpc.pb.go` に定義された `GreeterClient` インターフェースを使用して、サーバーのメソッドをリモートで呼び出します。
- このインターフェースを通じて `SayHello` メソッドを呼び出し、リクエストを送信し、レスポンスを受け取ります。
### 結論
生成された `.pb.go` と `_grpc.pb.go` ファイルは、gRPCサービスのクライアントとサーバーの骨組みを提供し、実際のビジネスロジックの実装に集中できるようにします。したがって、これらのファイルを見ながら `server.go` と `client.go` を書くことになります。これにより、プロトコルバッファの定義に忠実な型安全なコードを保証し、gRPCインフラストラクチャの多くの機能を自動的に活用できます。