github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/net/rpc/server.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  /*
     6  Package rpcは、オブジェクトのエクスポートされたメソッドに、ネットワークやその他のI/O接続を通じてアクセスする機能を提供します。サーバーはオブジェクトを登録し、オブジェクトのタイプ名に基づいてサービスとして表示されるようにします。登録後、オブジェクトのエクスポートされたメソッドはリモートからアクセス可能になります。サーバーは、異なるタイプの複数のオブジェクト(サービス)を登録することができますが、同じタイプの複数のオブジェクトを登録することはエラーです。
     7  
     8  以下の条件を満たすメソッドのみがリモートアクセス可能になります。それ以外のメソッドは無視されます:
     9  
    10    - メソッドの型がエクスポートされていること。
    11    - メソッドがエクスポートされていること。
    12    - メソッドが2つの引数を持ち、両方の引数がエクスポートされている(または組み込み)型であること。
    13    - メソッドの2番目の引数がポインタであること。
    14    - メソッドが戻り値としてerror型を持つこと。
    15  
    16  要するに、メソッドは次のようなスキーマである必要があります。
    17  
    18  	func (t *T) MethodName(argType T1, replyType *T2) error
    19  
    20  ここで、T1とT2はencoding/gobでマーシャリングできる型です。
    21  これらの要件は、異なるコーデックが使用されている場合でも適用されます。
    22  (将来的には、カスタムコーデックに対してこれらの要件は緩和されるかもしれません。)
    23  
    24  メソッドの最初の引数は呼び出し元から提供される引数を表し、
    25  2番目の引数は呼び出し元に返される結果パラメータを表します。
    26  メソッドの戻り値がnilでない場合、それはクライアントが [errors.New] によって作成されたかのようにクライアントが確認する文字列として送り返されます。
    27  エラーが返された場合、応答パラメータはクライアントに送り返されません。
    28  
    29  サーバーは、[ServeConn] を呼び出すことによって単一の接続上のリクエストを処理することができます。また、通常はネットワークリスナーを作成し、[Accept] を呼び出すか、HTTPリスナーの場合は [HandleHTTP] と [http.Serve] を呼び出します。
    30  
    31  サービスを使用するためには、クライアントは接続を確立し、その後、接続上で [NewClient] を呼び出します。[Dial]([DialHTTP])という便利な関数は、生のネットワーク接続(HTTP接続)に対して両方の手順を実行します。結果として得られる [Client] オブジェクトには、サービスとメソッドを指定するための2つのメソッド、[Call] とGoがあり、引数を含むポインタと結果パラメータを受け取るポインタを指定します。
    32  
    33  Callメソッドは、リモート呼び出しが完了するまで待機し、
    34  Goメソッドは非同期に呼び出しを開始し、Call構造体のDoneチャネルを使用して完了をシグナルします。
    35  
    36  明示的なコーデックが設定されていない場合、データの転送には [encoding/gob] パッケージが使用されます。
    37  
    38  以下にシンプルな例を示します。サーバーはArithタイプのオブジェクトをエクスポートしたい場合です。
    39  
    40  	package server
    41  
    42  	import "errors"
    43  
    44  	type Args struct {
    45  		A, B int
    46  	}
    47  
    48  	type Quotient struct {
    49  		Quo, Rem int
    50  	}
    51  
    52  	type Arith int
    53  
    54  	func (t *Arith) Multiply(args *Args, reply *int) error {
    55  		*reply = args.A * args.B
    56  		return nil
    57  	}
    58  
    59  	func (t *Arith) Divide(args *Args, quo *Quotient) error {
    60  		if args.B == 0 {
    61  			return errors.New("divide by zero")
    62  		}
    63  		quo.Quo = args.A / args.B
    64  		quo.Rem = args.A % args.B
    65  		return nil
    66  	}
    67  
    68  サーバーの呼び出し(HTTPサービスの場合):
    69  
    70  	arith := new(Arith)
    71  	rpc.Register(arith)
    72  	rpc.HandleHTTP()
    73  	l, err := net.Listen("tcp", ":1234")
    74  	if err != nil {
    75  		log.Fatal("listen error:", err)
    76  	}
    77  	go http.Serve(l, nil)
    78  
    79  この時点で、クライアントは"Arith"というサービスとそのメソッド"Arith.Multiply"、"Arith.Divide"を見ることができます。呼び出すためには、クライアントはまずサーバーにダイヤルします。
    80  
    81  	client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
    82  	if err != nil {
    83  		log.Fatal("dialing:", err)
    84  	}
    85  
    86  そして、リモート呼び出しを行うことができます。
    87  
    88  	// 同期呼び出し
    89  	args := &server.Args{7,8}
    90  	var reply int
    91  	err = client.Call("Arith.Multiply", args, &reply)
    92  	if err != nil {
    93  		log.Fatal("arith error:", err)
    94  	}
    95  	fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
    96  
    97  または
    98  
    99  	// 非同期呼び出し
   100  	quotient := new(Quotient)
   101  	divCall := client.Go("Arith.Divide", args, quotient, nil)
   102  	replyCall := <-divCall.Done	// divCallと等しい
   103  	// エラーをチェックし、出力などを行います。
   104  
   105  サーバーの実装では、クライアントのためのシンプルで型セーフなラッパーを提供することがよくあります。
   106  
   107  net/rpcパッケージは凍結されており、新しい機能は受け付けていません。
   108  */
   109  package rpc
   110  
   111  import (
   112  	"github.com/shogo82148/std/io"
   113  	"github.com/shogo82148/std/net"
   114  	"github.com/shogo82148/std/net/http"
   115  	"github.com/shogo82148/std/sync"
   116  )
   117  
   118  const (
   119  	// HandleHTTPで使用されるデフォルト値
   120  	DefaultRPCPath   = "/_goRPC_"
   121  	DefaultDebugPath = "/debug/rpc"
   122  )
   123  
   124  // RequestはRPC呼び出しの前に書かれるヘッダーです。内部で使用されますが、ネットワークトラフィックを分析する際などデバッグの支援のためにここで記述されています。
   125  type Request struct {
   126  	ServiceMethod string
   127  	Seq           uint64
   128  	next          *Request
   129  }
   130  
   131  // Responseは、すべてのRPCの戻り値の前に書かれるヘッダです。内部で使用されますが、ネットワークトラフィックを分析する際など、デバッグの支援としてここで文書化されています。
   132  type Response struct {
   133  	ServiceMethod string
   134  	Seq           uint64
   135  	Error         string
   136  	next          *Response
   137  }
   138  
   139  // ServerはRPCサーバーを表します。
   140  type Server struct {
   141  	serviceMap sync.Map
   142  	reqLock    sync.Mutex
   143  	freeReq    *Request
   144  	respLock   sync.Mutex
   145  	freeResp   *Response
   146  }
   147  
   148  // NewServerは新しい [Server] を返します。
   149  func NewServer() *Server
   150  
   151  // DefaultServerは [*Server] のデフォルトインスタンスです。
   152  var DefaultServer = NewServer()
   153  
   154  // Registerは、以下の条件を満たすレシーバーのメソッドのセットをサーバーに公開します:
   155  //   - エクスポートされた型のエクスポートされたメソッド
   156  //   - 2つの引数、両方がエクスポートされた型
   157  //   - 2番目の引数がポインタであること
   158  //   - エラー型の1つの戻り値
   159  //
   160  // レシーバーがエクスポートされた型でないか、適切なメソッドがない場合は、エラーを返します。また、エラーをパッケージlogを使用してログに記録します。
   161  // クライアントは "Type.Method" の形式の文字列を使用して各メソッドにアクセスします。ここで、Typeはレシーバーの具体的な型です。
   162  func (server *Server) Register(rcvr any) error
   163  
   164  // RegisterNameは [Register] と同様ですが、レシーバーの具体的な型の代わりに提供された名前を型に使用します。
   165  func (server *Server) RegisterName(name string, rcvr any) error
   166  
   167  // ServeConnは、単一の接続上でサーバーを実行します。
   168  // ServeConnは、クライアントが切断するまで接続を提供するためにブロックします。
   169  // 呼び出し元は通常、goステートメントでServeConnを呼び出します。
   170  // ServeConnは、接続上でgobワイヤーフォーマット(パッケージgobを参照)を使用します。
   171  // 代替のコーデックを使用するには、[ServeCodec] を使用します。
   172  // 並行アクセスに関する情報については、[NewClient] のコメントを参照してください。
   173  func (server *Server) ServeConn(conn io.ReadWriteCloser)
   174  
   175  // ServeCodecは [ServeConn] と同様ですが、指定されたコーデックを使用して
   176  // リクエストをデコードし、レスポンスをエンコードします。
   177  func (server *Server) ServeCodec(codec ServerCodec)
   178  
   179  // ServeRequestは [ServeCodec] と似ていますが、単一のリクエストを同期的に提供します。
   180  // 完了時にコーデックを閉じることはありません。
   181  func (server *Server) ServeRequest(codec ServerCodec) error
   182  
   183  // Acceptはリスナー上で接続を受け入れ、各受信接続のリクエストを処理します。
   184  // Acceptはリスナーがnon-nilのエラーを返すまでブロックされます。通常、呼び出し元はgoステートメントでAcceptを呼び出します。
   185  func (server *Server) Accept(lis net.Listener)
   186  
   187  // Registerはレシーバのメソッドを [DefaultServer] に登録します。
   188  func Register(rcvr any) error
   189  
   190  // RegisterNameは、レシーバの具体的な型ではなく、与えられた名前を型として使用します。[Register] と同様の動作です。
   191  func RegisterName(name string, rcvr any) error
   192  
   193  // ServerCodecはRPCセッションのサーバー側でのRPCリクエストの読み取りとRPCレスポンスの書き込みを実装します。
   194  // サーバーは [ServerCodec.ReadRequestHeader] と [ServerCodec.ReadRequestBody] をペアで呼び出して接続からリクエストを読み取り、[ServerCodec.WriteResponse] を呼び出してレスポンスを書き込みます。
   195  // サーバーは接続が終了したら [ServerCodec.Close] を呼び出します。ReadRequestBodyはnilの引数で呼び出されることがあり、リクエストの本文を読み取って破棄するためのものです。
   196  // 同時アクセスに関する情報については、[NewClient] のコメントを参照してください。
   197  type ServerCodec interface {
   198  	ReadRequestHeader(*Request) error
   199  	ReadRequestBody(any) error
   200  	WriteResponse(*Response, any) error
   201  
   202  	Close() error
   203  }
   204  
   205  // ServeConnは [DefaultServer] を単一の接続上で実行します。
   206  // ServeConnは、クライアントが切断するまで接続を処理するまでブロックします。
   207  // 通常、呼び出し元はgo文でServeConnを呼び出します。
   208  // ServeConnは、接続上でgobワイヤーフォーマット(パッケージgobを参照)を使用します。
   209  // 別のコーデックを使用するには、[ServeCodec] を使用してください。
   210  // 同時アクセスに関する情報については、[NewClient] のコメントを参照してください。
   211  func ServeConn(conn io.ReadWriteCloser)
   212  
   213  // ServeCodecは [ServeConn] と似ていますが、指定されたコーデックを使用して
   214  // リクエストをデコードし、レスポンスをエンコードします。
   215  func ServeCodec(codec ServerCodec)
   216  
   217  // ServeRequest は [ServeCodec] に似ていますが、単一のリクエストを同期的に処理します。
   218  // 処理が完了してもコーデックを閉じません。
   219  func ServeRequest(codec ServerCodec) error
   220  
   221  // Acceptはリスナー上で接続を受け付け、各受信された接続に対して [DefaultServer] にリクエストを処理します。
   222  // Acceptはブロックします。通常、呼び出し元はgo文でそれを呼び出します。
   223  func Accept(lis net.Listener)
   224  
   225  // ServeHTTPはRPCリクエストに答えるための [http.Handler] を実装します。
   226  func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request)
   227  
   228  // HandleHTTPはrpcPathでRPCメッセージのためのHTTPハンドラを登録し、debugPathではデバッグハンドラを登録します。
   229  // 通常はGoステートメント内で [http.Serve]()を呼び出す必要があります。
   230  func (server *Server) HandleHTTP(rpcPath, debugPath string)
   231  
   232  // HandleHTTPはRPCメッセージのためのHTTPハンドラを [DefaultServer] に登録し、[DefaultRPCPath] にデバッグハンドラを登録します。
   233  // 通常はgoステートメントで [http.Serve]()を呼び出す必要があります。
   234  func HandleHTTP()