Golangrpc 패키지 사용 안내

6254 단어 RPC
rpc 패키지는 네트워크나 기타I/0를 통해 연결된 대상에 대한 내보내기 방법에 대한 접근을 제공합니다.서버는 개체를 개체 유형 이름을 가진 가시적인 서비스로 등록합니다.등록 후 객체의 내보내기 방법에 원격으로 액세스할 수 있습니다.서버는 서로 다른 유형의 여러 대상 서비스를 등록할 수 있지만 같은 유형의 여러 대상을 등록하는 것은 잘못된 것이다.그리고 대상의 방법은 아래의 조건을 충족시켜야만 원격 호출을 사용할 수 있으며, 그렇지 않으면 방법은 무시될 수 있다.
  • 방법의 유형은 내보낼 수 있음
  • 방법은 도출된 것이다
  • 방법은 두 개의 매개 변수가 있는데 모두 내보낼 수 있다
  • 두 번째 파라미터는 바늘 유형
  • 이다.
  • 방법은 error 형식을 되돌려줍니다
  • 방법은 다음과 같습니다.
    func (t *T) MethodName(argType T1, replyType *T2) error
    
    T1T2encoding/gob를 통해 인코딩할 수 있다.방법의 첫 번째 파라미터는 호출자가 제공한 파라미터를 대표하고, 두 번째 파라미터는 호출자에게 되돌아오는 결과 파라미터를 대표한다.방법이 되돌아오는 값이 비어 있지 않으면 되돌아오는 reply 파라미터는 클라이언트에게 되돌아오지 않습니다.

    예제


    서버 프로세싱 프로세스

  • 우선 Register 또는 RegisterName를 사용하여 rpc 서비스를 등록한다.
  • 이어서 Listen 방법으로 로컬 네트워크의 주소를 직접 감청하고 정부에서 준 예에서 감청하기 전에 rpc.HandleHTTP 방법을 사용했다.
  • // rpc.HandleHTTP()
    
    func HandleHTTP() {
        DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
    }
    
    const (
        DefaultRPCPath  =   "/_goRPC_"
        DefaultDebug    =   "/debug/rpc"
    )
    
    func (server *Server) HandleHTTP(rpcPath, debugPath string) {
        http.Handle(rpcPath, server)
        http.Handle(debugPath, debugHTTP{server})
    }
    

    두 개handler를 등록하여 서비스 호출 상황을 볼 수 있습니다.예를 들어 Listen 감청localhost:1234 네트워크를 사용하면 루트localhost:1234/debug/rpc를 통해 다음과 같은 내용을 볼 수 있다.
  • 이어서 http.Serve 방법을 사용하여 다가올 HTTP 연결을 수신하고 각 연결에 새로운 서비스를 만들 것이다goroutine.모든 서비스는 요청을 읽고 handler 호출해서 그들에게 회답할 것입니다.handler는 보통nil이며, 이때DefaultServeMux는 사용된다.
  • func Serve(l net.Listener, handler Handler) error {
        srv := &Server{Handler: handler}
        return srv.Serve(l)
    }
    
    func (srv *Server) Serve(l net.Listener) error {
        // ...
        for {
            rw, e := l.Accept()
            if e != nil {
                // ...
            }
            c := srv.newConn(rw)
            c.setState(c.rwc, StateNew)
            go c.serve(ctx)
        }
    }
    

    위의 http.Serve 방법도 다른 방법으로 처리할 수 있다. 예를 들어 Accept 인터페이스와 ServeConn 방법, 그리고 for 문장을 사용하여 지속적인 처리 요청을 실현할 수 있다.두 번째 단계에서 Listen 방법은 listener 감청 대상을 되돌려주고 그 위에 Accept 방법을 호출한다.호출이 성공하면 사용 가능한 연결이 되돌아옵니다.그리고 rpc.ServeConn 방법을 사용해서 이 연결에서 기본 서비스를 실행합니다.ServeConn 클라이언트가 중단될 때까지 차단됩니다.보통 go를 사용하여 병발ServeConn하고, ServeConn 방법은 gob 형식의 codec를 사용하며, 교체가 필요하면 ServeCodec 방법을 사용합니다.rpc가방은 두 가지codec를 제공한다. 하나는 gob, 하나는 json이다.
    // ...
    listener, err := net.Listen("tcp", ":1234")
    if err != nil {
        fmt.Println("failed to listen tcp, error:",  err)
    }
    
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("failed to accept connection, error:", err)
        }
    
        go rpc.ServeConn(conn)
    }
    

    서버 전체 예

    package main
    
    import (
    	"errors"
    	"fmt"
    	"net"
    	"net/http"
    	"net/rpc"
    )
    
    type Args struct {
    	A, B int
    }
    
    type Quotient struct {
    	Quo, Rem int
    }
    
    type Arith int
    
    func (t *Arith) Multiply(args *Args, reply *int) error {
    	*reply = args.A * args.B
    	return nil
    }
    
    func (t *Arith) Divide(args *Args, quo *Quotient) error {
    	if args.B == 0 {
    		return errors.New("divide by zero")
    	}
    	quo.Quo = args.A / args.B
    	quo.Rem = args.A % args.B
    	return nil
    }
    
    func main() {
    	arith := new(Arith)
    	err := rpc.Register(arith)
    	if err != nil {
    		fmt.Println("failed to register rpc service. error: ", err)
    		return
    	}
    	rpc.HandleHTTP()
    	l, err := net.Listen("tcp", ":1234")
    	if err != nil {
    		fmt.Println("listen error:", err)
    	}
    	if err = http.Serve(l, nil); err != nil {
    		fmt.Println("failed to accept incoming request. error: ", err)
    		return
    	}
    }
    

    클라이언트 프로세스

  • 방법을 사용하여 특정 네트워크 주소의 Dial 서비스를 연결합니다.연결이 완료되면 새 클라이언트가 생성됩니다.RPC 방법도 사용할 수 있다. DialHTTP는 특정 네트워크 주소의 DialHTTP 서비스에 연결하고 기본값HTTP RPC 경로를 감청한다.
  • func DialHTTP(network, address string) (*Client, error) {
        return DialHTTPPath(network, address, DefaultRPCPath)
    }
    
    func DialHTTPPath(network, address, path string) (*Client, error) {
        var err error
        conn, err := net.Dial(network, address)
        if err != nil {
            return nil, err
        }
        // ...
    }
    
  • 첫 번째 단계에서 만든 클라이언트에서 HTTP RPC 인터페이스를 호출하고 Call 인터페이스는 지정한 Call 서비스를 호출하여 완료를 기다린 후 오류 상태를 되돌려줍니다.RPC 인터페이스는 동기화 호출Call 서비스로 비동기화 호출이 필요하면 클라이언트에서 호출RPC 인터페이스를 사용할 수 있습니다.
  • func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
        // ...
    }
    

    호출이 잘못되지 않았다면, 위에서 되돌아온 GoCall 채널은 오류가 없는 Done 로 전송될 것입니다.잘못 여부에 따라 호출 성공 여부를 판단할 수 있다.예를 들면 다음과 같습니다.
    // ...
    quotient := new(Quotient)
    divCall := client.Go("Arith.Divide", args, quotient, nil)
    replyCall := 

    클라이언트 전체 예

    package main
    
    import (
    	"fmt"
    	"net/rpc"
    )
    
    type Args struct {
    	A, B int
    }
    
    type Quotient struct {
    	Quo, Rem int
    }
    
    func main() {
    	client, err := rpc.DialHTTP("tcp", "127.0.0.1:1234")
    	if err != nil {
    		fmt.Println("failed to dial http rpc server, error:", err)
    	}
    
    	// Synchronous call
    	args := &Args{7, 8}
    	var reply int
    	if err = client.Call("Arith.Multiply", args, &reply); err != nil {
    		fmt.Println("failed to call function synchronously, error:", err)
    	}
    	fmt.Printf("Arith: %d*%d=%d
    ", args.A, args.B, reply) // Asynchronous call quotient := new(Quotient) divCall := client.Go("Arith.Divide", args, quotient, nil) replyCall :=

    좋은 웹페이지 즐겨찾기