Netpal
In diesem Beispiel möchte ich zeigen, wie man einen simplen TCP Echo-Server schreibt mit Hilfe vom Baseserver aus Netpal. Bevor man das hier liest sollte man vieleicht einen Blick auf die Funktionsweise geworfen haben.
Einführung
Mit der Hilfe von der BaseServer-Struktur braucht man für einen kompletten TCP-Server nur drei Funktionen zu implementieren, die sämtliche Netzwerkevents behandeln. Diese Funktionen bekommen als Parameter meist den Client, durch den ein Event erzeugt wurde und dazu eine Clientliste, welche sie auch zurück geben müssen.
Als erstes müssen wir den Fall behandeln, dass ein Client sich zu uns verbinden will. Dazu akzeptieren wir die Verbindung mit accept() und fügen ihn zur Client-Liste hinzu:
FUN openClient: seq[client] -> seq[client]
DEF openClient(list) == client(socket, <>) :: list
WHERE
-- seiteneffektbehafteter aufruf
socket == EXEC(sockaccept() & (
\\ sock. succeed(sock)))
Dann müssen wir uns um Daten vom Client kümmern. Wir bekommen vom BaseServer den Client, welcher uns etwas geschickt hat, die jeweiligen Daten als Denotation und die Client-Liste (incl. client). Wir schicken die Daten mit einem kleinen Kommentar zurück.
FUN procClient: client ** denotation ** seq[client] -> seq[client]
DEF procClient(client(csock, _), data, list) ==
EXEC(socksendto(msg, csock);
succeed(list))
WHERE
msg == "Du sagtest: " ++ data
Letztenendes müssen wir noch die Verbindung zum Client trennen können.
FUN closeClient: client ** seq[client] -> seq[client]
DEF closeClient(cli, list) ==
EXEC(sockcloseto(socket(cli));
succeed(newlist))
WHERE
newlist == removeClient(cli, list)
Nur noch in einen srvcore verpacken.
FUN echoserver: srvcore DEF echoserver == srvcore(openClient, procClient, closeClient)... und ausführen.
e runServer("31415"!, echoserver)
Natürlich ist dieses kurze Beispiel ziemlich EXEC-Lastig, aber der eigentliche Spaß kommt ja auch erst, wenn man anfängt ordentlich Daten in procClient zu verarbeiten. ;)
