2025年2月16日日曜日

Go言語入門(11)

Serverは32bit Windows実行ファイルで32bit Windows DLLを使って何か計算する。Clientは64bit Windows実行ファイルで自分が起動されたときにServerを自動的に起動して解放されるときにServerを閉じるってしたい。



Go言語入門(10)に間違いがあったのでその訂正も含めて全コードを載せちゃう。うざくてゴメン。
で、今回はclientを変更していくんだけど、以下のことをやる。
init関数(実行時に最初に勝手に実行される関数)を作って、そこでserverを起動するようにする。<--まぁコード見りゃわかるでしょ。
server起動を待ってRPC通信するようにする。
↑これは資料が少なすぎ、、、DialOption配列にgrpc.WithDefaultCallOptions(grpc.WaitForReady(true))を追加して、context.WithTimeoutのタイムアウトを少し長くするってした。
clientの実際の動作をmainから取り出して別関数にする。<--まぁコード見りゃわかるでしょ。
上記別関数の引数をC言語の型にする。<--これまでの取り組みを応用。とはいえ、もっといい方法があるかも、、、
、、、今回変化点多すぎ。

PATH="$PATH:$HOME/go/bin"
mkdir grpctry3
cd grpctry3
mkdir proto
mkdir server
mkdir client
go mod init grpc/grpctry3

proto/grpctry3.proto
  1. syntax = "proto3";
  2. package grpctry3;
  3. option go_package = "./proto";
  4. service MyAESEncrypter {
  5.   rpc AESEncrypt (Plain_and_Key) returns (Cipher) {}
  6. }
  7.  
  8. message Plain_and_Key {
  9.   bytes plain=1;
  10.   bytes key=2;
  11. }
  12.  
  13. message Cipher {
  14.   bytes result=1;
  15. }

server/main.go
  1. package main
  2.  
  3. import (
  4.     "context"
  5.     "flag"
  6.     "fmt"
  7.     "log"
  8.     "net"
  9.     "syscall"
  10.     "unsafe"
  11.  
  12.     pb "grpc/grpctry3/proto"
  13.  
  14.     "google.golang.org/grpc"
  15. )
  16.  
  17. var (
  18.     hdll, _ = syscall.LoadLibrary("rijndael.dll")
  19.     aes128encrypt, _ = syscall.GetProcAddress(hdll, "AES128Encrypt")
  20.     aes128decrypt, _ = syscall.GetProcAddress(hdll, "AES128Decrypt")
  21. )
  22.  
  23. func AES128Encrypt(plain *uint8, key *uint8, crypted *uint8) (r uint32) {
  24.     var nargs uintptr = 3
  25.     ret, _, _ := syscall.Syscall9(uintptr(aes128encrypt),
  26.         nargs,
  27.         uintptr(unsafe.Pointer(plain)),
  28.         uintptr(unsafe.Pointer(key)),
  29.         uintptr(unsafe.Pointer(crypted)),
  30.         0, 0, 0, 0, 0, 0)
  31.     r = uint32(ret)
  32.     return
  33. }
  34. func AES128Decrypt(crypted *uint8, key *uint8, plain *uint8) (r uint32) {
  35.     var nargs uintptr = 3
  36.     ret, _, _ := syscall.Syscall9(uintptr(aes128decrypt),
  37.         nargs,
  38.         uintptr(unsafe.Pointer(crypted)),
  39.         uintptr(unsafe.Pointer(key)),
  40.         uintptr(unsafe.Pointer(plain)),
  41.         0, 0, 0, 0, 0, 0)
  42.     r = uint32(ret)
  43.     return
  44. }
  45.  
  46. var (
  47.     port = flag.Int("port", 50051, "The server port")
  48. )
  49.  
  50. type server struct {
  51.     pb.UnimplementedMyAESEncrypterServer
  52. }
  53.  
  54. func (s *server) AESEncrypt(_ context.Context, in *pb.PlainAnd_Key) (*pb.Cipher, error) {
  55.     var d1 []byte = in.GetPlain()
  56.     var d2 []byte = in.GetKey()
  57.     var d1arr [16]byte = *(*[16]byte)(d1[:16])
  58.     var d2arr [16]byte = *(*[16]byte)(d2[:16])
  59.     var d3arr [16]byte
  60.     //defer syscall.FreeLibrary(hdll)
  61.     AES128Encrypt(&d1arr[0], &d2arr[0], &d3arr[0])
  62.     return &pb.Cipher{Result: d3arr[:]}, nil
  63. }
  64. func main() {
  65.     flag.Parse()
  66.     lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
  67.     if err != nil {
  68.         log.Fatalf("failed to listen: %v", err)
  69.     }
  70.     s := grpc.NewServer()
  71.     pb.RegisterMyAESEncrypterServer(s, &server{})
  72.     log.Printf("server listening at %v", lis.Addr())
  73.     if err := s.Serve(lis); err != nil {
  74.         log.Fatalf("failed to serve: %v", err)
  75.     }
  76.     defer syscall.FreeLibrary(hdll)
  77. }

clinet/main.go
  1. package main
  2.  
  3. /*
  4. #include <stdint.h>
  5. */
  6. import "C"
  7.  
  8. import (
  9.     "context"
  10.     "flag"
  11.     "fmt"
  12.     "log"
  13.     "os/exec"
  14.     "time"
  15.     "unsafe"
  16.  
  17.     pb "grpc/grpctry3/proto"
  18.  
  19.     "google.golang.org/grpc"
  20.     "google.golang.org/grpc/credentials/insecure"
  21. )
  22.  
  23. var (
  24.     addr = flag.String("addr", "localhost:50051", "the address to connect to")
  25. )
  26. var cmd *exec.Cmd
  27.  
  28. func init() {
  29.     srv_start_cmd := "./grpctry3_server.exe"
  30.     src_start_arg := ""
  31.     cmd = exec.Command(srv_start_cmd, src_start_arg)
  32.     cmd.Start()
  33.     fmt.Println(cmd.Process.Pid)
  34. }
  35.  
  36. type arr16 struct {
  37.     v [16]C.uint8_t
  38. }
  39.  
  40. func AES128Encrypt_grpcexec(cp *C.uint8_t, ck *C.uint8_t, cc *C.uint8_t) {
  41.     acp := (*arr16)(unsafe.Pointer(cp))
  42.     ack := (*arr16)(unsafe.Pointer(ck))
  43.     acc := (*arr16)(unsafe.Pointer(cc))
  44.     ppp := []byte{}
  45.     kkk := []byte{}
  46.     ccc := []byte{}
  47.     for i := 0; i < 16; i++ {
  48.         ppp = append(ppp, (uint8)((*acp).v[i]))
  49.         kkk = append(kkk, (uint8)((*ack).v[i]))
  50.     }
  51.     defer cmd.Process.Kill()
  52.  
  53.     // Set up a connection to the server.
  54.     dialOpts := []grpc.DialOption{
  55.         grpc.WithTransportCredentials(insecure.NewCredentials()),
  56.         grpc.WithDefaultCallOptions(grpc.WaitForReady(true)),
  57.     }
  58.  
  59.     conn, err := grpc.NewClient(*addr, dialOpts...)
  60.     if err != nil {
  61.         log.Fatalf("did not connect: %v", err)
  62.     }
  63.     defer conn.Close()
  64.     c := pb.NewMyAESEncrypterClient(conn)
  65.  
  66.     // Contact the server and print out its response.
  67.     ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  68.     defer cancel()
  69.     r, err := c.AESEncrypt(ctx, &pb.PlainAnd_Key{Plain: ppp, Key: kkk})
  70.     if err != nil {
  71.         log.Fatalf("could not greet: %v", err)
  72.     }
  73.     ccc = r.GetResult()
  74.     for i := 0; i < 16; i++ {
  75.         (*acc).v[i] = (C.uint8_t)(ccc[i])
  76.     }
  77. }
  78. func main() {
  79.     p := [...]C.uint8_t{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}
  80.     k := [...]C.uint8_t{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
  81.     c := [...]C.uint8_t{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
  82.     fmt.Printf("% 02X\n", p)
  83.     fmt.Printf("% 02X\n", k)
  84.     AES128Encrypt_grpcexec(&p[0], &k[0], &c[0])
  85.     fmt.Printf("% 02X\n", c)
  86. }

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/grpctry3.proto
go get google.golang.org/grpc
cd server
GOOS=windows GOARCH=386 go build -o ../grpctry3_server.exe main.go
cd ..
cd client
CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o ../grpctry3_client.exe main.go
cd ..
で、こうなってる。
  • .
  • ├── client
  • │ └── main.go
  • ├── go.mod
  • ├── go.sum
  • ├── grpctry3_client.exe
  • ├── grpctry3_server.exe
  • ├── proto
  • │ ├── grpctry3.pb.go
  • │ ├── grpctry3.proto
  • │ └── grpctry3_grpc.pb.go
  • ├── rijndael.dll
  • └── server
  •   └── main.go
で、実行ファイルたちはこんな感じ。

で、実行させるとこんな感じ。

うまくいっている。serverがRPCを受け入れられる状態になっていない状態でRPCするとclientでエラーになるってんで、どうやって回避するのかってのを調べるのがしんどかった。この辺の情報が少ないんよねー、、、てか、やりたいことが特殊なのかな、、、

0 件のコメント:

コメントを投稿