この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:2
ページ更新者:T
更新日時:2023-11-22 20:56:56

タイトル: 詳細説明付きクイックスタート
SEOタイトル: 詳細説明付きgRPCクイックスタート

 

※執筆中

公式のクイックスタートの詳しい解説をします。

 

要インストール

$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2

※「protoc」コマンドをターミナル / コマンドプロンプトで実行できるようにPATHを通してください。(OS毎に操作が異なるので省略します)

 

サンプルコードの入手

以下のコマンドでサンプルコードを入手しましょう。

$ git clone -b v1.59.0 --depth 1 https://github.com/grpc/grpc-go

 

基本的の以下の「helloworld」プロジェクトしか使用しませんので移動しましょう。

$ cd grpc-go/examples/helloworld

 

サンプルアプリの実行

とりあえずサンプルアプリを動かしてみましょう。

詳細の解説は後程。

 

まずはサーバー側を起動します。

$ go run greeter_server/main.go

 

続けて同じくターミナル / コマンドプロンプトをもう一つ開き、クライアントを起動します。

$ go run greeter_client/main.go
Greeting: Hello world

上記のコマンドを実行すると、サーバー側のターミナルで「Received: world」と表示されれば成功です。

 

greeter_client/main.goの説明

var (
    addr = flag.String("addr", "localhost:50051", "the address to connect to")
    name = flag.String("name", defaultName, "Name to greet")
)

ここでは、コマンドライン引数として受け取るための変数 addr(サーバーアドレス)と name(挨拶する相手の名前)を定義しています。

flagパッケージは、コマンドライン引数を処理するためのGo言語の標準ライブラリです。このパッケージを使用することで、プログラムを実行する際にコマンドライン引数を指定できます。

flag.Parse() の呼び出しは、flag パッケージがコマンドライン引数を解釈し、各フラグの値を更新するために必要です。コマンドライン引数を解釈しないと、各フラグの値はデフォルトのままとなります。

※今回は引数なしで実行しているので、上記の2つ目の引数で指定されているデフォルト値である「localhost:50051」、「defaultName」が採用されます。
 

conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
    log.Fatalf("did not connect: %v", err)
}
defer conn.Close()

gRPCサーバーへの接続を確立します。

また、セキュリティ設定として insecure.NewCredentials() を使用しています。

grpc.Dial は、指定されたアドレスに対してgRPCサーバーへの接続を確立します。

 

c := pb.NewGreeterClient(conn)

HelloWorldサービスのgRPCクライアントを作成します。

 

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("Greeting: %s", r.GetMessage())

サーバーに挨拶を要求して、その結果を出力します。context.WithTimeout を使用して、タイムアウトが発生した場合にコンテキストがキャンセルされるようにします。

このクライアントは、指定された名前でHelloWorldサービスに挨拶を送り、サーバーからの応答をログに出力します。
 

greeter_server/main.goの説明

以下のプログラムごとのコメントをまずざっくりご確認ください。

詳細は後述します。

// コマンドライン引数を処理するための変数
var (
    port = flag.Int("port", 50051, "The server port")
)

// HelloWorldサービスのgRPCサーバーを実装する構造体
type server struct {
    pb.UnimplementedGreeterServer
}

 

// GreeterサービスのSayHelloメソッドの実装
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() {

    // client側のmain.goの説明を参照

    flag.Parse()
    
    // サーバーポートでリッスン ※詳細は後述
    lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    
    // gRPCサーバーを作成
    s := grpc.NewServer()
    
    // Greeterサービスをサーバーに登録
    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)
    }
}

このコードはgRPCを使用してHelloWorldサービスに対するサーバーを実装しており、コマンドライン引数からポート番号を指定してサーバーを起動します。※今回は引数がないのでデフォルト値です。

サーバーはクライアントからの挨拶リクエストを受け付け、応答として挨拶メッセージを返します。

 

lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))

この行は、gRPCサーバーがリッスンするネットワークアドレスを設定しています。具体的には、TCPネットワークを指定し、指定されたポート番号で接続を受け入れるための net.Listener インターフェースを作成しています。

詳細を解説します:

  1. fmt.Sprintf(":%d", *port) は、指定されたポート番号 *port を文字列に変換し、その後にコロン : を付け加えています。これにより、指定されたポート番号のTCPアドレスが作成されます。

  2. net.Listen("tcp", ...) は、TCPネットワークを指定してリッスン用の net.Listener インターフェースを生成します。具体的には、指定されたTCPアドレスでクライアントからの接続を待ち受けるように設定されます。

  3. lis, err := ... は、net.Listen の戻り値として得られる net.Listener インターフェースとエラーを取得します。エラーが発生した場合は、err にエラーが格納され、それに対処することができます。

したがって、この行全体で言えば、サーバーは指定されたポート番号でTCPアドレスをリッスンし、クライアントからの接続を待ち受ける net.Listener インターフェースを取得しています。

 

 

a

 

a

 

a

 

a

 

a

 

a

 

a