goとgRPCを使用した例

## 内容
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インフラストラクチャの多くの機能を自動的に活用できます。