Heim > Backend-Entwicklung > Golang > RPC Action EPIimplementieren Sie eine einfache RPC-Schnittstelle in Go

RPC Action EPIimplementieren Sie eine einfache RPC-Schnittstelle in Go

PHPz
Freigeben: 2024-09-09 18:30:11
Original
998 Leute haben es durchsucht

RPC Action EPImplement a simple RPC interface in Go

RPC (Remote Procedure Call) ist eine weit verbreitete Kommunikationsmethode zwischen verschiedenen Knoten in verteilten Systemen und eine grundlegende Technologie des Internetzeitalters. Die Standardbibliothek von Go bietet eine einfache Implementierung von RPC unter dem Paket net/rpc. Dieser Artikel soll Ihnen helfen, RPC zu verstehen, indem er Sie durch die Implementierung einer einfachen RPC-Schnittstelle mithilfe des Pakets net/rpc führt.

Dieser Artikel wurde zuerst im Medium MPP-Plan veröffentlicht. Wenn Sie ein Medium-Benutzer sind, folgen Sie mir bitte auf Medium. Vielen Dank.

Damit eine Funktion aus der Ferne in net/rpc aufgerufen werden kann, muss sie die folgenden fünf Bedingungen erfüllen:

  • Der Typ der Methode wird exportiert.
  • Die Methode wird exportiert.
  • Die Methode verfügt über zwei Argumente, die beide exportierte (oder integrierte) Typen sind.
  • Das zweite Argument der Methode ist ein Zeiger.
  • Die Methode weist einen Fehler vom Typ Rückgabe auf.

Mit anderen Worten, die Funktionssignatur muss wie folgt lauten:

func (t *T) MethodName(argType T1, replyType *T2) error
Nach dem Login kopieren

Erstellen einer einfachen RPC-Anfrage

Basierend auf diesen fünf Bedingungen können wir eine einfache RPC-Schnittstelle erstellen:

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

Als nächstes können Sie ein Objekt vom Typ HelloService als RPC-Dienst registrieren:

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)  
    }
}
Nach dem Login kopieren

Die clientseitige Implementierung ist wie folgt:

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)
}
Nach dem Login kopieren

Zuerst wählt der Client den RPC-Dienst mit rpc.Dial an und ruft dann über client.Call() eine bestimmte RPC-Methode auf. Der erste Parameter ist der RPC-Dienstname und der Methodenname in Kombination mit einem Punkt, der zweite ist die Eingabe und der dritte ist der Rückgabewert, der ein Zeiger ist. Dieses Beispiel zeigt, wie einfach die Verwendung von RPC ist.

Sowohl im Server- als auch im Client-Code müssen wir uns den RPC-Dienstnamen HelloService und den Methodennamen Hello merken. Dies kann während der Entwicklung leicht zu Fehlern führen, sodass wir den Code leicht umbrechen können, indem wir die gemeinsamen Teile abstrahieren. Der vollständige Code lautet wie folgt:

// 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)  
    }  
}
Nach dem Login kopieren
// 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)
}
Nach dem Login kopieren

Kommt es Ihnen bekannt vor?

Implementierung des JSON-Codecs mit dem net/rpc-Paket von Go

Standardmäßig verwendet die Standard-RPC-Bibliothek von Go die proprietäre Gob-Kodierung. Es ist jedoch problemlos, darüber hinaus auch andere Kodierungen wie Protobuf oder JSON zu implementieren. Die Standardbibliothek unterstützt bereits die JSONRPC-Kodierung, und wir können die JSON-Kodierung implementieren, indem wir geringfügige Änderungen am Server- und Client-Code vornehmen.

// 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  
}
Nach dem Login kopieren

Das JSON-Anforderungsdatenobjekt entspricht intern zwei Strukturen: auf der Clientseite ist es clientRequest und auf der Serverseite ist es serverRequest. Der Inhalt der Strukturen clientRequest und serverRequest ist im Wesentlichen derselbe:

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"`  
}
Nach dem Login kopieren

Methode stellt hier den Dienstnamen dar, der aus serviceName und Methode besteht. Das erste Element von Params ist der Parameter, und Id ist eine eindeutige Rufnummer, die vom Anrufer verwaltet wird und zur Unterscheidung von Anforderungen in gleichzeitigen Szenarien verwendet wird.

Wir können nc verwenden, um den Server zu simulieren und dann den Client-Code ausführen, um zu sehen, welche Informationen der JSON-codierte Client an den Server sendet:

 nc -l 1234
Nach dem Login kopieren

Der NC-Befehl empfängt die folgenden Daten:

 {"method":"HelloService.Hello","params":["hello"],"id":0}
Nach dem Login kopieren

Dies stimmt mit serverRequest überein.

Wir können auch den Servercode ausführen und nc verwenden, um eine Anfrage zu senden:

echo -e '{"method":"HelloService.Hello","params":["Hello"],"Id":1}' | nc localhost 1234 
--- 
{"id":1,"result":"hello:Hello","error":null}
Nach dem Login kopieren

Abschluss

In diesem Artikel wurde das RPC-Paket aus der Standardbibliothek von Go vorgestellt und dessen Einfachheit und leistungsstarke Leistung hervorgehoben. Viele RPC-Bibliotheken von Drittanbietern bauen auf dem RPC-Paket auf. Dieser Artikel ist der erste Teil einer Reihe zur RPC-Forschung. Im nächsten Artikel werden wir Protobuf mit RPC kombinieren und schließlich unser eigenes RPC-Framework implementieren.

Das obige ist der detaillierte Inhalt vonRPC Action EPIimplementieren Sie eine einfache RPC-Schnittstelle in Go. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage