Rpcgen – Interne Funktionsweise

Aus dev.kaibel.net
Zur Navigation springen Zur Suche springen

rpcgen – Interne Funktionsweise

Diese Seite beschreibt die interne Arbeitsweise des Werkzeugs rpcgen und wie es auf niedriger Ebene die Kommunikation zwischen Client und Server über das Netzwerk mit Hilfe von Remote Procedure Calls (RPC) realisiert.

Sie ergänzt den Artikel rpcgen (C-Werkzeug) und erklärt insbesondere, wie rpcgen:

  • RPC-Code generiert,
  • Datenstrukturen in übertragbare Formate (XDR) wandelt,
  • Stub-Funktionen für Client und Server erzeugt,
  • und wie die eigentliche Netzwerkkommunikation technisch abläuft.

---

Architekturüberblick

rpcgen ist ein Code-Generator für das ONC-RPC-System (*Open Network Computing Remote Procedure Call*), ursprünglich von Sun Microsystems entwickelt. Es setzt auf drei Schichten auf:

+--------------------------+
|   Benutzerprogramm       |  (Client / Server Implementierung)
+--------------------------+
|   RPC-Stubs (von rpcgen) |  (Client-Stub, Server-Stub)
+--------------------------+
|   XDR & RPC-Laufzeit     |  (libc / libtirpc)
+--------------------------+
|   Transport (UDP/TCP)    |
+--------------------------+

---

1. Der rpcgen-Codegenerator

rpcgen verarbeitet eine Schnittstellenbeschreibung (Datei *.x*) und erzeugt daraus automatisch mehrere C-Dateien:

Datei Beschreibung
name.h Enthält Funktionsprototypen und Konstanten (Program-, Versions- und Prozedur-IDs)
name_xdr.c Enthält Funktionen zur XDR-Datenkonvertierung
name_clnt.c Enthält Client-Stubs für RPC-Aufrufe
name_svc.c Enthält Server-Stubs, die eingehende RPCs verarbeiten

---

2. XDR – External Data Representation

RPC verwendet das XDR-Format (External Data Representation), um Daten plattformunabhängig zu übertragen.

Jede Struktur, die in der .x-Datei definiert ist, erhält automatisch eine passende XDR-Funktion:

bool_t xdr_structname(XDR* xdrs, struct structname* objp);

Die Funktion arbeitet je nach Modus:

  • **ENCODE** – Daten werden in Netzwerkformat serialisiert
  • **DECODE** – Daten werden aus Netzwerkformat deserialisiert

Beispiel:

bool_t xdr_intpair(XDR *xdrs, intpair *objp) {
    return xdr_int(xdrs, &objp->a) &&
           xdr_int(xdrs, &objp->b);
}

Damit können Systeme mit unterschiedlicher Endianness (Little/Big Endian) sicher kommunizieren.

---

3. Die generierten Stubs

rpcgen erzeugt zwei Stub-Schichten:

Client-Stubs (name_clnt.c)

Diese Funktionen sehen für den Programmierer wie lokale Funktionsaufrufe aus, führen intern aber eine Netzwerkübertragung aus.

Beispiel:

int *add_1(intpair *argp, CLIENT *clnt) {
    static int res;
    memset(&res, 0, sizeof(res));

    if (clnt_call(clnt, ADD,
                  (xdrproc_t)xdr_intpair, (caddr_t)argp,
                  (xdrproc_t)xdr_int, (caddr_t)&res,
                  TIMEOUT) != RPC_SUCCESS) {
        return NULL;
    }
    return &res;
}

Hier ruft clnt_call() die RPC-Laufzeitfunktion aus der Bibliothek libtirpc auf, die: 1. die Daten per XDR kodiert, 2. über UDP oder TCP an den Server sendet, 3. auf die Antwort wartet, 4. das Ergebnis dekodiert und zurückgibt.

---

Server-Stubs (name_svc.c)

Diese Funktionen verarbeiten eingehende RPC-Anfragen. Sie werden automatisch von der Funktion svc_run() aufgerufen, sobald ein Client eine RPC-Anfrage sendet.

Beispiel:

static void calcprog_1(struct svc_req *rqstp, SVCXPRT *transp) {
    union {
        intpair add_1_arg;
    } argument;
    int result;
    bool_t retval = FALSE;

    memset(&argument, 0, sizeof(argument));
    if (!svc_getargs(transp, (xdrproc_t)xdr_intpair, (caddr_t)&argument)) {
        svcerr_decode(transp);
        return;
    }

    result = *add_1_svc(&argument, rqstp);
    svc_sendreply(transp, (xdrproc_t)xdr_int, (char*)&result);
}

---

4. Ablauf einer RPC-Kommunikation

Client                         Server
---------------------------------------------------------
| add_1(&p)                  |                          |
|   → clnt_call()            |                          |
|       → send via UDP/TCP   |                          |
|                            | svc_run() empfängt       |
|                            | → svc_getargs()          |
|                            | → add_1_svc()            |
|                            | → svc_sendreply()        |
|   ← Ergebnis empfangen     |                          |
---------------------------------------------------------
    • Kurz gesagt:**

- Der Client ruft eine Stub-Funktion auf. - Der Stub serialisiert Argumente und sendet sie an den Server. - Der Server-Stub empfängt, dekodiert, ruft die echte Funktion auf und schickt das Ergebnis zurück.

---

5. Transport und Protokolle

rpcgen unterstützt mehrere Transportarten:

  • **UDP** – schnell, verbindungslos, nicht zuverlässig
  • **TCP** – zuverlässig, verbindungsorientiert
  • **RAW** – intern für Tests

Die Bibliothek `libtirpc` (oder ältere `libc`-Implementierungen) übernimmt den Netzwerkcode vollständig. Beispiel:

CLIENT *clnt = clnt_create("localhost", CALCPROG, CALCVERS, "tcp");

---

6. Der Portmapper

Damit Client und Server einander finden, nutzt ONC-RPC den Portmapper-Dienst (Programmnummer 100000, Port 111). Der Server registriert sich beim Portmapper:

svc_register(transp, CALCPROG, CALCVERS, calcprog_1, IPPROTO_TCP);

Der Client fragt beim Portmapper den tatsächlichen Port für das Programm CALCPROG ab. Dadurch kann RPC auch dynamische Ports verwenden.

---

7. Lebenszyklus eines rpcgen-Projekts

1. .x-Datei definieren (Datentypen & Prozeduren)
2. rpcgen aufrufen → erzeugt Code
3. Server-Implementierung schreiben (z. B. *_svc.c erweitern)
4. Client-Programm schreiben
5. Beide kompilieren und starten
6. Client ruft Funktionen auf → RPC läuft automatisch über Netzwerk

---

8. Fehlerbehandlung und Rückgabecodes

RPC-Funktionen geben in der Regel über enum clnt_stat oder enum auth_stat Fehler zurück, z. B.:

  • RPC_SUCCESS – Erfolg
  • RPC_TIMEDOUT – Timeout
  • RPC_AUTHERROR – Authentifizierungsfehler
  • RPC_CANTSEND – Senden fehlgeschlagen

Fehlerausgabe erfolgt meist über:

clnt_perror(clnt, "Fehler bei RPC");

---

9. Vergleich mit modernen Technologien

| Technologie | Beschreibung | |--------------|--------------| | **ONC RPC (rpcgen)** | Klassisches C-basiertes RPC-System | | **gRPC (Google RPC)** | Moderne, Protobuf-basierte Variante mit HTTP/2 | | **XML-RPC / JSON-RPC** | Textbasierte, plattformunabhängige Alternativen | | **D-Bus** | IPC für Linux-Desktop-Systeme |

rpcgen ist sehr performant, aber weniger flexibel für heterogene oder moderne Webumgebungen.

---

Siehe auch

Quellen

  • Sun Microsystems: rpcgen User’s Guide
  • Stevens, W. Richard: UNIX Network Programming, Vol. 1, Prentice Hall.
  • Linux Manual: man rpcgen, man 3 rpc
  • RFC 5531 – Open Network Computing (ONC) Remote Procedure Call (RPC)