SebaGeek Lectus non solum ad dormiendum factus est.

Netpal

Überblick

Der Einfachheit halber beschränkt sich Netpal momentan auf TCP mit entweder einem Server-Socket und n Clients oder einem Client-Socket. Das ließe sich zwar relativ einfach umgehen, würde aber sowohl die Benutzbarkeit erschweren, als auch einiges mehr an Arbeit bedeuten.

Aufbau

Netpal besteht momentan aus drei Schichten:
  1. Netpal.hc.c - Der C-Teil
  2. Netpal.impl - Die Opalabstraktion
  3. BaseServer.impl - Weitere Abstraktion

Netpal.hc.c - Der C-Teil

Die C Implementation stellt die Schnittstelle von Opal zu den Systemcalls dar. Für eine Netzwerkanwendung brauchen wir Socket öffnen, Socket schliessen, Daten senden, Daten empfangen und die FD-SET Funktionen.

Zum Socket öffnen sind einige Schritte nötig, welche von der Funktion _ANetpal_Asockopen ("_A{Modulname}_A{funktionsname}" ist das vorgeschriebene Pattern für Opal-C-Funktionen) übernommen werden. Man gibt ihr eine IP/Port Kombination und bekommt dafür einen Socket zurück. Der Socket wird in einem internen struct namens netdata gespeichert, um das Handling zu vereinfachen. Parameterlose Netzwerkfunktionen arbeiten automatisch mit diesem Socket. Für einige gibt es noch einen parametrisierten Ersatz, um als Server mit mehreren Clients zu arbeiten.

Client

In der Client.impl wird eine Datenstruktur client definiert, die für die folgenden Strukturen wichtig ist. Er besteht aus einer natürlichen Zahl, welche seinen Socket darstellt und ausserdem einer Sequenz aus Denotations, welche seinen State darstellen. Da es keine direkten globalen Variablen gibt, welche als State benutzt werden können, muss immer eine Liste mit allen momentan verbundenen Clients übergeben werden. Der Server nimmt hier auch den Status eines Clients an. Identifiziert werden kann er durch seinen Socket, welcher über die Funktion getServerSocket() identifiziert werden kann. Optional kann man dem Server auch ein "IS_SERVER"-Flag in seinen State packen.

Weiterhin gibt es ein paar Listen-Helper für den Client, welche aber größtenteils selbsterklärend sein sollten.

Netpal.impl - Die Opalabstraktion

Hier werden einerseits die Handcoded-Funktionen mit einem FUN definiert, teils aber auch von anderen Funktionen als "Funktionen mit Seiteneffekten" gemappt.

Ausserdem findet hier noch das "select" statt. sockselect packt alle Clients in ein FD_SET, lässt dann ein select drüber laufen und gibt eine Liste von Clients zurück, welche ein Event ausgelöst haben.

BaseServer.impl - Weitere Abstraktion

BaseServer fügt das Ganze erst zu einem richtigen Server zusammen. Hier wird der Socket geöffnet, das Select gestartet und jeweils die Clients behandelt: Client öffnet Verbindung, Client sendet Daten, Client schließt die Verbindung.

Das Interessante ist hier das Interface: Der Benutzer von Netpal kann runServer() einen Port und einen sog. srvcore übergeben. Letzterer besteht aus drei Funktionen, welche bei den oben genannten Events gecallt werden. Wichtig ist, dass sie jeweils mindestens die Liste aller Clients bekommen und diese auch - ggf. mit veränderten Clients - zurückgeben müssen.

openClient(clients) öffnet einen Socket und fügt ihn der Liste hinzu.
procClient(client, data, clients) behandelt vom Client gesendete Daten.
closeClient(client, clients) schließt den Socket zum Client und löscht ihn aus der Liste.

Um das ganze etwas zu veranschaulichen gibt es hier auch ein Beispiel.

π