Programowanie aplikacji klient-serwer
Zewnętrzna reprezentacja danych
XDR
Standard XDR
Problem: każdy komputer może inaczej numerować bajty, w których przechowywane są dane.
Problemu nie rozwiązuje proste odwrócenie bajtów:
Rozwiązanie: zewnętrzna reprezentacja danych niezależna od komputera i umożliwiająca ich przesyłanie.
Zasada działania:
klient i serwer przed wysłaniem danych przekształcają je z postaci wewnętrznej do standardowej postaci zewnętrznej;
klient i serwer odbierając dane z sieci przekształcają je do postaci wewnętrznej obowiązującej w danym systemie
Standard XDR (ang. eXternal Data Representation, RFC 1014) - specyfikacja zewnętrznej reprezentacji danych określająca postać przesyłania w sieci danych powszechnie używanych typów
(opracowany przez Sun Microsystems)
Reprezentacja danych w formacie XDR
Dane są zawsze zapisywane jako wielokrotność czterech bajtów (32 bitów).
Bajty są numerowane od 0 do n-1 (ang. big endian)
Bajty są pisane lub czytane ze strumienia bajtów w taki sposób, że bajt m zawsze poprzedza bajt m+1.
Jeśli n bajtów potrzebnych do przesłania danych nie jest wielokrotnością 4, uzupełniane są zerami do najbliższej wielokrotności 4.
Przykłady definicji XDR:
Liczby całkowite bez znaku :
Liczby całkowite ze znakiem zapisywane są w kodzie uzupełnień do dwóch.
Liczby rzeczywiste zapisywane są w 32 bitowym formacie IEEE (1 bit znaku, 8 bitów wykładnika i 23 bity podstawy)
Napisy zapisywane są za pomocą pola długość, po którym umieszczane są kolejne znaki napisu, uzupełnione znakiem NULL do wielokrotności czterech bajtów.
Tablice zapisywane są za pomocą pola rozmiar (liczba całkowita zajmująca cztery bajty) po którym umieszczane są kolejne elementy. Pole rozmiar jest pomijane w wypadku tablic stałej długości.
Filtry konwersji XDR
Są to funkcje w języku C służące do konwersji danych z postaci wewnętrznej komputera do postaci XDR i odwrotnie.
Typ danych |
Filtr |
Typy podstawowe języka C |
|
char |
xdr_char(3N) |
short int |
xdr_short(3N) |
unsigned short int |
xdr_u_short(3N) |
int |
xdr_int(3N) |
unsigned int |
xdr_u_int(3N) |
long |
xdr_long(3N) |
unsigned long |
xdr_u_long(3N) |
float |
xdr_float(3N) |
double |
xdr_double(3N) |
void |
xdr_void(3N) |
enum |
xdr_enum(3N) |
bool_t(C int) |
xdr_bool(3N) |
Typy złożone |
|
tablica zmiennej długości |
xdr_array(3N) |
tablica bajtów o podanej długości |
xdr_bytes(3N) |
ciąg bajtów określonej długości przesyłanych bez konwersji |
xdr_opaque(3N) |
wskaźniki |
xdr_pointer(3N) |
napisy |
xdr_string(3N) |
tablice stałej długości |
xdr_vector(3N) |
Strumienie XDR
Strumień XDR to ciąg bajtów, w którym dane są reprezentowane w formacie XDR.
Nadawca wywołuje funkcje biblioteki XDR, które przekształcają kolejne dane w formacie własnym do formatu zewnętrznego XDR i umieszczają w strumieniu.
Odbiorca czyta dane w formacie zewnętrznym ze strumienia i przekształca je do własnej postaci.
Funkcja konwersji XDR dokonuje konwersji w obydwu kierunkach. Wywołana funkcja stwierdza, w którym kierunku należy wykonać konwersję na podstawie informacji zawartej w strumieniu XDR na którym działa.
XDR_ENCODE - kodowanie danych w strumieniu
XDR_DECODE - dekodowanie danych w strumieniu
Typy strumieni
Strumień w pamięci
Dane do przesłania są przygotowywane w buforze i wysyłane za pomocą funkcji we-wy (np. write)
Potok jest jednokierunkowy, trzeba określić typ: XDR_ENCODE lub XDR_DECODE
Funkcja tworzenia strumienia: xdrmem_create(3N)
#include <rpc/xdr.h>
#define BUFSIZE 4000 /* rozmiar bufora */
XDR xdrs; /* identyfikator strumienia */
char buf[BUFSIZE]; /* obszar dla danych XDR */
/* incjalizacja strumienia w trybie ENCODE */
xdrmem_create(xdrs,buf,BUFSIZE, XDR_ENCODE);
int i;
i=260;
/* konwersja i dołączenie do strumienia */
xdr_int(&xdrs,&i);
...
/* wysłanie strumienia */
Strumień przyłączony do pliku
Strumień można przyłączyć do pliku za pomocą mechanizmów standardowego wejścia-wyjścia, wtedy operacje pisania i czytania wykonywane są automatycznie gdy wywołana zostanie funkcja konwersji.
Potok jest jednokierunkowy, trzeba określić typ: XDR_ENCODE lub XDR_DECODE
Funkcja tworzenia strumienia: xdrstdio_create(3N)
#include <rpc/xdr.h>
FILE *fp; /* wskaźnik pliku */
XDR xdrs; /* wskaźnik strumienia */
fp=fopen("xdrplik","w") /* otwarcie pliku */
/* incjalizacja strumienia w trybie ENCODE */
xdrstdio_create(&xdrs,fp, XDR_ENCODE);
int i;
i=260;
/* konwersja i przesłanie do pliku */
xdr_int(&xdrs,&i);
.....
Strumień podzielony na rekordy
Strumień można dzielić na rekordy.
Funkcja tworzenia strumienia pozwala określić procedury wyprowadzające i wprowadzające dane.
Każda procedura wykonująca konwersję danych do postaci zewnętrznej sprawdza, czy bufor jest już pełny. Jeśli tak, to wywołuje procedurę wyprowadzającą, aby wysłać zawartość bufora.
Każda procedura wykonująca konwersję danych z postaci zewnętrznej do własnej sprawdza, czy są dane w buforze. Jeśli bufor jest pusty, to wywołuje procedurę wprowadzającą, w celu wprowadzenia danych do bufora.
Funkcja tworzenia strumienia: xdrrec_create(3N)
#include <rpc/xdr.h>
FILE *fp; /* wskaźnik pliku */
XDR xdrs; /* wskaźnik strumienia */
/* procedura czytania */
int readp(FILE *fp, char *buf, unsigned int n);
/* procedura pisania */
int writep(FILE *fp, char *buf, unsigned int n);
fp=fopen("xdrplik","w") /* otwarcie pliku */
/* incjalizacja strumienia w trybie ENCODE */
xdrreco_create(&xdrs,0,0,fp,readp,writep);
xdrs.x_op=XDR_ENCODE;
int i,j;
i=260;
j=350;
/* konwersja i przesłanie do bufora */
xdr_int(&xdrs,&i);
xdr_int(&xdrs,&j);
/* koniec rekordu - opróżnij bufor */
xdrrec_endofrecord(&xdrs,TRUE);
32 bity
bajt 3
bajt 2
bajt 1
bajt 0
Proces nadawca
Strumień XDR
Strumień XDR
Proces odbiorca
0
0
0
3
0
1
2
3
J
O
L
A
Komputer A:
liczba 3
napis JOLA
Komputer B:
liczba 50 331 648
napis JOLA
A
L
O
J
3
2
1
0
0
0
0
3
przesłanie
do komputera B
J
O
L
A
3
2
1
0
3
0
0
0
Komputer B:
liczba 3
napis ALOJ
32 bity
bajt 3
bajt 2
bajt 1
bajt 0
S
E
M
konwersja
konwersja