RPC Action EPGo에서 간단한 RPC 인터페이스 구현

PHPz
풀어 주다: 2024-09-09 18:30:11
원래의
771명이 탐색했습니다.

RPC Action EPImplement a simple RPC interface in Go

RPC(Remote Procedure Call)는 분산 시스템에서 서로 다른 노드 사이에 널리 사용되는 통신 방식으로 인터넷 시대의 기반 기술입니다. Go의 표준 라이브러리는 net/rpc 패키지에서 간단한 RPC 구현을 제공합니다. 이 글의 목표는 net/rpc 패키지를 사용하여 간단한 RPC 인터페이스를 구현하는 과정을 안내하여 RPC에 대한 이해를 돕는 것입니다.

이 글은 Medium MPP 기획에 처음 게재되었습니다. 미디엄 사용자라면 미디엄에서 저를 팔로우해주세요. 정말 감사합니다.

net/rpc에서 원격으로 함수를 호출하려면 다음 5가지 조건을 충족해야 합니다.

  • 메소드 유형을 내보냅니다.
  • 방법을 내보냅니다.
  • 이 메소드에는 두 개의 인수가 있으며 둘 다 내보낸(또는 내장) 유형입니다.
  • 메서드의 두 번째 인수는 포인터입니다.
  • 메서드에 오류 반환 유형이 있습니다.

즉, 함수 서명은 다음과 같아야 합니다.

func (t *T) MethodName(argType T1, replyType *T2) error
로그인 후 복사

단순 RPC 요청 생성

이 다섯 가지 조건을 바탕으로 간단한 RPC 인터페이스를 구성할 수 있습니다.

type HelloService struct{}  
func (p *HelloService) Hello(request string, reply *string) error {  
    log.Println("HelloService Hello")  
    *reply = "hello:" + request  
    return nil  
}
로그인 후 복사

다음으로 HelloService 유형의 개체를 RPC 서비스로 등록할 수 있습니다.

func main() {
    _ = rpc.RegisterName("HelloService", new(HelloService))  
    listener, err := net.Listen("tcp", ":1234")  
    if err != nil {  
        log.Fatal("ListenTCP error:", err)  
    }  
    for {  
        conn, err := listener.Accept()  
        if err != nil {  
           log.Fatal("Accept error:", err)  
        }  
        go rpc.ServeConn(conn)  
    }
}
로그인 후 복사

클라이언트측 구현은 다음과 같습니다.

func main() {
    conn, err := net.Dial("tcp", ":1234")
    if err != nil {
        log.Fatal("net.Dial:", err)
    }
    client := rpc.NewClient(conn)
    var reply string
    err = client.Call("HelloService.Hello", "hello", &reply)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(reply)
}
로그인 후 복사

먼저 클라이언트는 rpc.Dial을 사용하여 RPC 서비스에 전화를 걸고 client.Call()을 통해 특정 RPC 메서드를 호출합니다. 첫 번째 매개변수는 점으로 결합된 RPC 서비스 이름과 메소드 이름이고, 두 번째 매개변수는 입력, 세 번째 매개변수는 반환 값인 포인터입니다. 이 예는 RPC를 사용하는 것이 얼마나 쉬운지 보여줍니다.

서버와 클라이언트 코드 모두에서 RPC 서비스 이름 HelloService와 메서드 이름 Hello를 기억해야 합니다. 이는 개발 중에 쉽게 오류로 이어질 수 있으므로 공통 부분을 추상화하여 코드를 약간 래핑할 수 있습니다. 전체 코드는 다음과 같습니다.

// server.go
const ServerName = "HelloService"  

type HelloServiceInterface = interface {  
    Hello(request string, reply *string) error  
}  

func RegisterHelloService(srv HelloServiceInterface) error {  
    return rpc.RegisterName(ServerName, srv)  
}  

type HelloService struct{}  

func (p *HelloService) Hello(request string, reply *string) error {  
    log.Println("HelloService Hello")  
    *reply = "hello:" + request  
    return nil  
}

func main() {  
    _ = RegisterHelloService(new(HelloService))  
    listener, err := net.Listen("tcp", ":1234")  
    if err != nil {  
       log.Fatal("ListenTCP error:", err)  
    }  
    for {  
       conn, err := listener.Accept()  
       if err != nil {  
          log.Fatal("Accept error:", err)  
       }  
       go rpc.ServeConn(conn)  
    }  
}
로그인 후 복사
// client.go

type HelloServiceClient struct {  
    *rpc.Client  
}  

var _ HelloServiceInterface = (*HelloServiceClient)(nil)  

const ServerName = "HelloService" 

func DialHelloService(network, address string) (*HelloServiceClient, error) {  
    conn, err := net.Dial(network, address)  
    client := rpc.NewClient(conn)  
    if err != nil {  
       return nil, err  
    }  
    return &HelloServiceClient{Client: client}, nil  
}

func (p *HelloServiceClient) Hello(request string, reply *string) error {  
    return p.Client.Call(ServerName+".Hello", request, reply)  
}
func main() {
    client, err := DialHelloService("tcp", "localhost:1234")  
    if err != nil {  
        log.Fatal("net.Dial:", err)  
    }  
    var reply string  
    err = client.Hello("hello", &reply)  
    if err != nil {  
        log.Fatal(err)  
    }  
    fmt.Println(reply)
}
로그인 후 복사

낯익은 것 같나요?

Go의 net/rpc 패키지로 JSON 코덱 구현

기본적으로 Go의 표준 RPC 라이브러리는 Go의 독점 Gob 인코딩을 사용합니다. 그러나 그 위에 Protobuf 또는 JSON과 같은 다른 인코딩을 구현하는 것은 간단합니다. 표준 라이브러리는 이미 jsonrpc 인코딩을 지원하며 서버 및 클라이언트 코드를 약간 변경하여 JSON 인코딩을 구현할 수 있습니다.

// server.go
func main() {  
    _ = rpc.RegisterName("HelloService", new(HelloService))  
    listener, err := net.Listen("tcp", ":1234")  
    if err != nil {  
       log.Fatal("ListenTCP error:", err)  
    }  
    for {  
       conn, err := listener.Accept()  
       if err != nil {  
          log.Fatal("Accept error:", err)  
       }  
       go rpc.ServeCodec(jsonrpc.NewServerCodec(conn))  
       //go rpc.ServeConn(conn)  
    }  
}

//client.go
func DialHelloService(network, address string) (*HelloServiceClient, error) {  
    conn, err := net.Dial(network, address)  
    //client := rpc.NewClient(conn)  
    client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))  
    if err != nil {  
       return nil, err  
    }  
    return &HelloServiceClient{Client: client}, nil  
}
로그인 후 복사

JSON 요청 데이터 개체는 내부적으로 두 가지 구조, 즉 클라이언트 측에서는 clientRequest이고, 서버 측에서는 serverRequest에 해당합니다. clientRequest 및 serverRequest 구조의 내용은 기본적으로 동일합니다.

type clientRequest struct {  
    Method string `json:"method"`  
    Params [1]any `json:"params"`  
    Id     uint64 `json:"id"`  
}
type serverRequest struct {  
    Method string           `json:"method"`  
    Params *json.RawMessage `json:"params"`  
    Id     *json.RawMessage `json:"id"`  
}
로그인 후 복사

여기서 Method는 serviceName과 Method로 구성된 서비스 이름을 나타냅니다. Params의 첫 번째 요소는 매개변수이며, Id는 호출자가 유지하는 고유한 호출 번호로 동시 시나리오에서 요청을 구별하는 데 사용됩니다.

nc를 사용하여 서버를 시뮬레이션한 다음 클라이언트 코드를 실행하여 JSON으로 인코딩된 클라이언트가 서버에 보내는 정보를 확인할 수 있습니다.

 nc -l 1234
로그인 후 복사

nc 명령은 다음 데이터를 받습니다.

 {"method":"HelloService.Hello","params":["hello"],"id":0}
로그인 후 복사

이는 serverRequest와 일치합니다.

서버 코드를 실행하고 nc를 사용하여 요청을 보낼 수도 있습니다.

echo -e '{"method":"HelloService.Hello","params":["Hello"],"Id":1}' | nc localhost 1234 
--- 
{"id":1,"result":"hello:Hello","error":null}
로그인 후 복사

결론

이 기사에서는 Go 표준 라이브러리의 rpc 패키지를 소개하여 단순성과 강력한 성능을 강조했습니다. 많은 타사 rpc 라이브러리는 rpc 패키지 위에 구축됩니다. 이 기사는 RPC 연구 시리즈의 첫 번째 기사입니다. 다음 글에서는 protobuf를 RPC와 결합하여 최종적으로 자체 RPC 프레임워크를 구현해 보겠습니다.

위 내용은 RPC Action EPGo에서 간단한 RPC 인터페이스 구현의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!