← レッスン一覧に戻る

解答 03.4 — RPC(Multiply)¶

このノートブックは 03.4-rpc.ipynb の練習問題の解答です。 まず問題の前提コードを再掲し、次に解答、最後にチェックを実行します。

先に自分の力で解いてから、答え合わせに使ってください。

前提コード(問題ノートブックと同じ定義)¶

In [1]:
import (
	"errors"
	"fmt"
	"net"
	"net/rpc"
	"time"
)

// ErrUnanswered は、練習問題が未回答のときにプレースホルダ関数が返す特別なエラー。
var ErrUnanswered = errors.New("未回答: この関数はまだ実装されていません")

type MathService struct{}

type AddArgs struct {
	A, B float64
}

func (m *MathService) Add(args AddArgs, reply *float64) error {
	*reply = args.A + args.B
	return nil
}

// newPipeRPC は net.Pipe() 越しに MathService を公開したサーバーと、
// それに繋がったクライアントを1組作る。呼び出し側は必ず client.Close() → <-done(有限待機)まで行うこと。
func newPipeRPC() (client *rpc.Client, done chan struct{}) {
	server := rpc.NewServer()
	if err := server.Register(new(MathService)); err != nil {
		panic(err)
	}

	clientConn, serverConn := net.Pipe()
	done = make(chan struct{})
	go func() {
		defer close(done)
		server.ServeConn(serverConn)
	}()

	client = rpc.NewClient(clientConn)
	return client, done
}

func waitDone(done chan struct{}) {
	select {
	case <-done:
	case <-time.After(2 * time.Second):
		fmt.Println("⚠️ サーバーgoroutineがタイムアウトした(client.Close()が呼ばれたか確認してください)")
	}
}

解答: Multiply¶

Add と同じ形(func (m *MathService) M(args AddArgs, reply *float64) error)で、 *reply に積をセットするだけです。

In [2]:
func (m *MathService) Multiply(args AddArgs, reply *float64) error {
	*reply = args.A * args.B
	return nil
}

チェック(問題ノートブックと同じ期待値)¶

答え合わせ用のヘルパー mustEqual を定義します。

In [3]:
import "reflect"

func mustEqual(got, want any, name string) {
	if reflect.DeepEqual(got, want) {
		fmt.Printf("✅ Passed: %s\n", name)
		return
	}
	panic(fmt.Sprintf("❌ %s\n  got  = %v (%T)\n  want = %v (%T)", name, got, got, want, want))
}
In [4]:
%%
client, done := newPipeRPC()

var product float64
mulErr := client.Call("MathService.Multiply", AddArgs{A: 6, B: 7}, &product)

client.Close()
waitDone(done)

mustEqual(mulErr, nil, "Multiply はエラーなし")
mustEqual(product, float64(42), "Multiply(6, 7) = 42")
fmt.Println("🎉 すべてのチェックが通りました")
✅ Passed: Multiply はエラーなし
✅ Passed: Multiply(6, 7) = 42
🎉 すべてのチェックが通りました

解説¶

  1. Add と同じ形: net/rpc のメソッドは func (t *T) M(args T1, reply *T2) error という決まった 形さえ守れば、既存メソッドをコピーしてロジックだけ変えるだけで新しいRPCメソッドを追加できます
  2. 登録は自動: server.Register(new(MathService)) は MathService の全てのエクスポートされた メソッドをまとめて登録するため、Multiply を追加しても再登録のコードは不要です(同じ newPipeRPC のままで新しいメソッドが呼べるようになります)