- 概要
- サンプルについて
- gRPC を動作させる上で必要なものをインストール
- protoファイルを作成
- protoファイルからGoのコードを生成
- サービスを実装
- サーバとクライアントを実装
- 実行してみる
- 通信内容を覗いてみる
- おすすめ書籍
概要
少し前に Unix ドメインソケット のメモを書いたのですが
ついでなので、gRPC で Unix ドメインソケット のサンプルも作ってみました。
サンプルについて
今回もサンプルはついでなので github にアップしてあります。良かったらご参照ください。
gRPC を動作させる上で必要なものをインストール
gRPC を Go で動作させるには
- protocol buffers の コンパイラ protoc
- grpc の Go ライブラリ
が必要になります。インストールについては以下の記事にとてもわかり易く書いてくださってる方がいます。感謝 m( )m
上の記事を見ながらインストールしてもいいのですが、gRPCでサンプル書くたびに打つの面倒なので
gistに makefile アップしときました。
gRPC と Go のプログラム作るときに使えるmakefile
この makefile 落として
make install-requirements
ってやるとprotocとかgRPCのライブラリを落としてきます。
ご利用される場合は、makefile内の protoc のURLとかprotocの生成物の置き場所とかを適時ご自身の環境に調整ください。
私は Crostini (Chromebook の Linux) で作業していますので、ARM64版 (aarch64) のprotoc を使っています。
protoファイルを作成
セットアップが終わったら、次は protoファイルの作成です。
以下のようにしました。
syntax = "proto3"; package echo; option go_package = "internal/pb"; service Echo { rpc Echo (EchoMessage) returns (EchoResponse) {} } message EchoMessage { string data = 1; } message EchoResponse { string data = 1; }
protoファイルからGoのコードを生成
次に protoファイル からGoのコードを生成します。
上で載せている makefile には、すでにタスクを定義してあります。
make protoc
で生成されます。
サービスを実装
以下のように実装しました。リクエスト受けたデータを大文字にして返すだけです。
package service import ( "context" "strings" "github.com/devlights/go-grpc-uds-example/internal/pb" ) type EchoServiceImpl struct { } var _ pb.EchoServer = (*EchoServiceImpl)(nil) func NewEchoService() pb.EchoServer { return new(EchoServiceImpl) } func (e *EchoServiceImpl) Echo(ctx context.Context, message *pb.EchoMessage) (*pb.EchoResponse, error) { s := strings.ToUpper(message.Data) r := &pb.EchoResponse{ Data: s, } return r, nil }
サーバとクライアントを実装
後は、それを呼び出すコードをサーバとクライアント分書けばいいだけです。楽ですねー gRPC。
サーバ側
gRPC で Unix ドメインソケットを利用する場合、サーバ側は特別違いはありません。
普通にリスナーを作って、それを gRPC にホストしてもらうように設定すれば終わりです。
package main import ( "log" "net" "os" "github.com/devlights/go-grpc-uds-example/internal/pb" "github.com/devlights/go-grpc-uds-example/internal/service" "google.golang.org/grpc" ) const ( protocol = "unix" sockAddr = "/tmp/echo.sock" ) func main() { // - https://qiita.com/marnie_ms4/items/4582a1a0db363fe246f3 // - http://yamahiro0518.hatenablog.com/entry/2016/02/01/215908 cleanup := func() { if _, err := os.Stat(sockAddr); err == nil { if err := os.RemoveAll(sockAddr); err != nil { log.Fatal(err) } } } cleanup() listener, err := net.Listen(protocol, sockAddr) if err != nil { log.Fatal(err) } server := grpc.NewServer() echo := service.NewEchoService() pb.RegisterEchoServer(server, echo) server.Serve(listener) }
クライアント側
クライアント側は、いつもの gRPC の Dial 呼び出しと少し変わります。
そのままだと、TCPになってしまうので、オプションで Dialer を渡すようにします。
それ以降は、いつもどおりです。
package main import ( "context" "fmt" "log" "net" "time" "github.com/devlights/go-grpc-uds-example/internal/pb" "google.golang.org/grpc" ) const ( protocol = "unix" sockAddr = "/tmp/echo.sock" ) func main() { // - https://qiita.com/marnie_ms4/items/4582a1a0db363fe246f3 // - http://yamahiro0518.hatenablog.com/entry/2016/02/01/215908 dialer := func(addr string, t time.Duration) (net.Conn, error) { return net.Dial(protocol, addr) } conn, err := grpc.Dial(sockAddr, grpc.WithInsecure(), grpc.WithDialer(dialer)) if err != nil { log.Fatal(err) } defer conn.Close() var ( client = pb.NewEchoClient(conn) rootCtx = context.Background() timeout = 1 * time.Second values = []string{ "hello world", "golang", "goroutine", "this program runs on crostini", } ) for _, v := range values { func() { ctx, cancel := context.WithTimeout(rootCtx, timeout) defer cancel() message := pb.EchoMessage{Data: v} res, err := client.Echo(ctx, &message) if err != nil { log.Println(err) return } fmt.Println(res) }() } }
実行してみる
実行すると以下のようになります。
$ make run go run cmd/server/server.go & sleep 1 go run cmd/client/client.go data:"HELLO WORLD" data:"GOLANG" data:"GOROUTINE" data:"THIS PROGRAM RUNS ON CROSTINI" sleep 1 pkill server true signal: terminated
ちゃんと大文字になって返ってきていますね。通信の送受信部分を一切自分で書いていないのに動いてくれるって、とても便利。
通信内容を覗いてみる
どんなデータが流れているのでしょうか。Unixドメインソケットの通信データを覗く方法は上にリンク貼ってる前々回の記事を参照ください。
私の環境では以下のようになっていました。
> 2020/08/26 12:55:25.623421 length=33 from=0 to=32 50 52 49 20 2a 20 48 54 54 50 2f 32 2e 30 0d 0a PRI * HTTP/2.0.. 0d 0a .. 53 4d 0d 0a SM.. 0d 0a .. 00 00 00 04 00 00 00 00 00 ......... -- < 2020/08/26 12:55:25.625373 length=15 from=0 to=14 00 00 06 04 00 00 00 00 00 00 05 00 00 40 00 .............@. -- < 2020/08/26 12:55:25.625875 length=9 from=15 to=23 00 00 00 04 01 00 00 00 00 ......... -- > 2020/08/26 12:55:25.626531 length=9 from=33 to=41 00 00 00 04 01 00 00 00 00 ......... -- > 2020/08/26 12:55:25.627203 length=116 from=42 to=157 00 00 50 01 04 00 00 00 01 83 86 45 8b 60 a4 9c ..P........E.`.. eb e0 24 e7 63 01 27 3f 41 8a 61 34 d6 c1 49 39 ..$.c.'?A.a4..I9 d7 41 c9 d7 5f 8b 1d 75 d0 62 0d 26 3d 4c 4d 65 .A.._..u.b.&=LMe 64 7a 8a 9a ca c8 b4 c7 60 2b b2 15 c3 40 02 74 dz......`+...@.t 65 86 4d 83 35 05 b1 1f 40 89 9a ca c8 b2 4d 49 e.M.5...@.....MI 4f 6a 7f 85 7d f6 84 27 6d 00 00 12 00 01 00 00 Oj..}..'m....... 00 01 00 00 00 00 0d 0a ........ 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64 .hello world -- < 2020/08/26 12:55:25.630630 length=30 from=24 to=53 00 00 04 08 00 00 00 00 00 00 00 00 12 00 00 08 ................ 06 00 00 00 00 00 02 04 10 10 09 0e 07 07 .............. -- < 2020/08/26 12:55:25.631389 length=83 from=54 to=136 00 00 0e 01 04 00 00 00 01 88 5f 8b 1d 75 d0 62 .........._..u.b 0d 26 3d 4c 4d 65 64 00 00 12 00 00 00 00 00 01 .&=LMed......... 00 00 00 00 0d 0a ...... 0b 48 45 4c 4c 4f 20 57 4f 52 4c 44 00 00 18 01 .HELLO WORLD.... 05 00 00 00 01 40 88 9a ca c8 b2 12 34 da 8f 01 .....@......4... 30 40 89 9a ca c8 b5 25 42 07 31 7f 00 0@.....%B.1.. -- > 2020/08/26 12:55:25.633103 length=17 from=158 to=174 00 00 08 06 01 00 00 00 00 02 04 10 10 09 0e 07 ................ 07 . -- > 2020/08/26 12:55:25.635127 length=76 from=175 to=250 00 00 04 08 00 00 00 00 00 00 00 00 12 00 00 08 ................ 06 00 00 00 00 00 02 04 10 10 09 0e 07 07 00 00 ................ 0f 01 04 00 00 00 03 83 86 c3 c2 c1 c0 bf 7e 86 ..............~. 7d f7 df 69 9b 7f 00 00 0d 00 01 00 00 00 03 00 }..i............ 00 00 00 08 0a ..... 06 67 6f 6c 61 6e 67 .golang -- < 2020/08/26 12:55:25.642211 length=91 from=137 to=227 00 00 08 06 01 00 00 00 00 02 04 10 10 09 0e 07 ................ 07 00 00 04 08 00 00 00 00 00 00 00 00 0d 00 00 ................ 08 06 00 00 00 00 00 02 04 10 10 09 0e 07 07 00 ................ 00 02 01 04 00 00 00 03 88 c0 00 00 0d 00 00 00 ................ 00 00 03 00 00 00 00 08 0a ......... 06 47 4f 4c 41 4e 47 00 00 02 01 05 00 00 00 03 .GOLANG......... bf be .. -- > 2020/08/26 12:55:25.651475 length=47 from=251 to=297 00 00 08 06 01 00 00 00 00 02 04 10 10 09 0e 07 ................ 07 00 00 04 08 00 00 00 00 00 00 00 00 0d 00 00 ................ 08 06 00 00 00 00 00 02 04 10 10 09 0e 07 07 ............... -- > 2020/08/26 12:55:25.654727 length=49 from=298 to=346 00 00 0f 01 04 00 00 00 05 83 86 c4 c3 c2 c1 c0 ................ 7e 86 7d f7 de 79 ab 7f 00 00 10 00 01 00 00 00 ~.}..y.......... 05 00 00 00 00 0b 0a ....... 09 67 6f 72 6f 75 74 69 6e 65 .goroutine -- < 2020/08/26 12:55:25.657198 length=17 from=228 to=244 00 00 08 06 01 00 00 00 00 02 04 10 10 09 0e 07 ................ 07 . -- < 2020/08/26 12:55:25.658443 length=77 from=245 to=321 00 00 04 08 00 00 00 00 00 00 00 00 10 00 00 08 ................ 06 00 00 00 00 00 02 04 10 10 09 0e 07 07 00 00 ................ 02 01 04 00 00 00 05 88 c0 00 00 10 00 00 00 00 ................ 00 05 00 00 00 00 0b 0a ........ 09 47 4f 52 4f 55 54 49 4e 45 00 00 02 01 05 00 .GOROUTINE...... 00 00 05 bf be ..... -- > 2020/08/26 12:55:25.664361 length=47 from=347 to=393 00 00 08 06 01 00 00 00 00 02 04 10 10 09 0e 07 ................ 07 00 00 04 08 00 00 00 00 00 00 00 00 10 00 00 ................ 08 06 00 00 00 00 00 02 04 10 10 09 0e 07 07 ............... -- > 2020/08/26 12:55:25.665495 length=69 from=394 to=462 00 00 0f 01 04 00 00 00 07 83 86 c5 c4 c3 c2 c1 ................ 7e 86 7d f7 df 65 bb 7f 00 00 24 00 01 00 00 00 ~.}..e....$..... 07 00 00 00 00 1f 0a ....... 1d 74 68 69 73 20 70 72 6f 67 72 61 6d 20 72 75 .this program ru 6e 73 20 6f 6e 20 63 72 6f 73 74 69 6e 69 ns on crostini -- < 2020/08/26 12:55:25.667152 length=17 from=322 to=338 00 00 08 06 01 00 00 00 00 02 04 10 10 09 0e 07 ................ 07 . -- < 2020/08/26 12:55:25.668900 length=97 from=339 to=435 00 00 04 08 00 00 00 00 00 00 00 00 24 00 00 08 ............$... 06 00 00 00 00 00 02 04 10 10 09 0e 07 07 00 00 ................ 02 01 04 00 00 00 07 88 c0 00 00 24 00 00 00 00 ...........$.... 00 07 00 00 00 00 1f 0a ........ 1d 54 48 49 53 20 50 52 4f 47 52 41 4d 20 52 55 .THIS PROGRAM RU 4e 53 20 4f 4e 20 43 52 4f 53 54 49 4e 49 00 00 NS ON CROSTINI.. 02 01 05 00 00 00 07 bf be ......... --
ちゃんと最初にHTTP/2.0から始まっていますね。送っているデータはとても単純なデータなのですが内部でいろいろ付与されているので、それなりにバイト数が増えています。まあ、それでも少ないですが。
おすすめ書籍
自分が読んだGo関連の本で、いい本って感じたものです。
- 作者:Katherine Cox-Buday
- 発売日: 2018/10/26
- メディア: 単行本(ソフトカバー)
- 作者:松尾 愛賀
- 発売日: 2016/04/15
- メディア: 単行本(ソフトカバー)
プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
- 作者:Alan A.A. Donovan,Brian W. Kernighan
- 発売日: 2016/06/20
- メディア: 単行本(ソフトカバー)
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場