2025年2月6日木曜日

Go言語入門(9)

興味本位でGo言語に触れてみようと思う。WSLでGoでgRPCをやってみる。バイト配列(ていうかスライスって位置づけ?)を入力して、バイト配列を受け取るっていうRPC。64bit Windows実行ファイルを作って動作を確認することろまで。



exampleを少し抜け出して、自分なりのものを作ってみる。とはいってもサーバーやらクライアントやらの基本的な記述はGreeterそのまんま。実際に処理をする関数だけを自分発のものにする。で、exampleを単純にコピペして進めたらはまることがあって、これって先にやっておくべきものなので、先にやっておく。こんなのgRPCのQuick startにもBasics turotialにも書いてない。Go言語の仕様からくるものなので説明がないのかもしれないけど、手っ取り早く動くものを作りたいって人にとってはこういうのが挫折の原因になると思うので、改善してほしい。まじで。で、
mkdir grpctry1
cd grpctry1
mkdir proto
mkdir server
mkdir client
go mod init grpc/grpctry1
最後のやつでgo.modなるものができている。これやらんとはまる。よくよく思い出すとそんなんやったなー最初のころ。
では、各フォルダに必要なものを作っていく。

proto/grpctry1.proto
  1. syntax = "proto3";
  2. package grpctry1;
  3. option go_package = "./proto";
  4. service MyConnector {
  5.   rpc Connect (ConnectRequest) returns (ConnectReply) {}
  6. }
  7.  
  8. message ConnectRequest {
  9.   bytes data_in1=1;
  10.   bytes data_in2=2;
  11. }
  12.  
  13. message ConnectReply {
  14.   bytes data_out=1;
  15. }
protoでbytesを含むメッセージを定義するんだけど、これって配列じゃなくて、sliceってのになるらしい。grpctry1.pb.goを見るとわかる。Go言語で配列とsliceは似ているけど違うもので、一発で代入できたりはしなくて、さもなくば、[16]byteを[]byteに代入できるわけないやろこのゴミカスがって怒られる。

server/main.go
  1. package main
  2.  
  3. import (
  4.     "context"
  5.     "flag"
  6.     "fmt"
  7.     "log"
  8.     "net"
  9.  
  10.     pb "grpc/grpctry1/proto"
  11.  
  12.     "google.golang.org/grpc"
  13. )
  14.  
  15. var (
  16.     port = flag.Int("port", 50051, "The server port")
  17. )
  18.  
  19. // server is used to implement helloworld.GreeterServer.
  20. type server struct {
  21.     pb.UnimplementedMyConnectorServer
  22. }
  23.  
  24. // SayHello implements helloworld.GreeterServer
  25. func (s *server) Connect(_ context.Context, in *pb.ConnectRequest) (*pb.ConnectReply, error) {
  26.     var d1 []byte = in.GetDataIn1()
  27.     var d2 []byte = in.GetDataIn2()
  28.     d3 := []byte{}
  29.     for i := 0; i < 16; i++ {
  30.         d3 = append(d3, d1[i])
  31.     }
  32.     log.Println("")
  33.     for i := 0; i < 16; i++ {
  34.         d3 = append(d3, d2[i])
  35.     }
  36.  
  37.     return &pb.ConnectReply{DataOut: d3}, nil
  38. }
  39. func main() {
  40.     flag.Parse()
  41.     lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
  42.     if err != nil {
  43.         log.Fatalf("failed to listen: %v", err)
  44.     }
  45.     s := grpc.NewServer()
  46.     pb.RegisterMyConnectorServer(s, &server{})
  47.     log.Printf("server listening at %v", lis.Addr())
  48.     if err := s.Serve(lis); err != nil {
  49.         log.Fatalf("failed to serve: %v", err)
  50.     }
  51. }
sliceにsliceを連結させるのって一発でできそうだけどあえてループで1つづつ要素を追加ってやり方にしている。

client/main.go
  1. package main
  2.  
  3. import (
  4.     "context"
  5.     "flag"
  6.     "fmt"
  7.     "log"
  8.     "time"
  9.  
  10.     pb "grpc/grpctry1/proto"
  11.  
  12.     "google.golang.org/grpc"
  13.     "google.golang.org/grpc/credentials/insecure"
  14. )
  15.  
  16. var (
  17.     addr = flag.String("addr", "localhost:50051", "the address to connect to")
  18. )
  19.  
  20. func main() {
  21.     d1 := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
  22.     d2 := []byte{1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8}
  23.     flag.Parse()
  24.     // Set up a connection to the server.
  25.     conn, err := grpc.NewClient(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
  26.     if err != nil {
  27.         log.Fatalf("did not connect: %v", err)
  28.     }
  29.     defer conn.Close()
  30.     c := pb.NewMyConnectorClient(conn)
  31.  
  32.     // Contact the server and print out its response.
  33.     ctx, cancel := context.WithTimeout(context.Background(), time.Second)
  34.     defer cancel()
  35.     r, err := c.Connect(ctx, &pb.ConnectRequest{DataIn1: d1, DataIn2: d2})
  36.     if err != nil {
  37.         log.Fatalf("could not greet: %v", err)
  38.     }
  39.     var d3 []byte = r.GetDataOut()
  40.     fmt.Printf("% 02X\n", d3)
  41. }

以上。
proto/grpctry1.ptoroの
option go_package = "./proto";
とか、
server/main.goの
pb "grpc/grpctry1/proto"
とか、 client/main.goの
pb "grpc/grpctry1/proto"
とか、まじでなぞ。まじで呪文。
で、実行してみる。
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/grpctry1.proto
go run server/main.go
そすっと、
まぁ、こんな感じで怒られるので凹む。
go get google.golang.org/grpc
ってやればいいっぽいので、それやって、改めて実行してみる。
とりあえず、動くにはうごいたらしい。
ctrl+cでいったん止めて、わかりやすい感じでserverとclientを実行してみる。こうなる。
はい。よくできました。
protocで生成されるpb.goファイルを見る(理解する必要はない)ってところが実は重要だと思った。
ではWindows実行ファイルを作る。
cd server
GOOS=windows GOARCH=amd64 go build -o grpctry1_server.exe main.go
cd ../client
GOOS=windows GOARCH=amd64 go build -o grpctry1_client.exe main.go
cd ..
で、各フォルダに実行ファイルができたので、エクスプローラーでアドレスバーに\\wsl$っていれてWSLのファイルシステムを掘っていって実行ファイルをWindows側に取り出して、例によって実行許可を与えて、で、実行。
ちなみにserverを起動すると、こういうのがでる。許可するしかない。
で、こうなる。
いいぞ。、、、てか、ファイルサイズがマジクソデカくないか?

フリーアドレスをやめる<--翌日のリスタートが早くなるので業務効率が上がる。
組織改編は4月とする<--1~3月の無駄な作業がなくなるので業務効率が上がる。
エレベーターの横のボタンは押さない※<--その階で扉が開くのが遅くなることの防止となるので業務効率が上がる。
(※それが必要な方がそれをすることは正当な行為であり妨げない)
まずは簡単にできるところからやってくれんかな。

0 件のコメント:

コメントを投稿