MenuetOS The Assembly Language Programmers OS!


Home | Das Wiki | Screenshots | Dokumente | Downloads | Foren | Kontakt

Stack Interface

Von Version 0.78, die folgenden Features sind im TCP/IP Stack-Code vorhanden: Und die folgenden Internet Anwendungen sind implementiert Es sind ebenfalls einige experimentelle Anwendungen für Musik-Streaming und Interprozesskommunikation über Sockets. Ein Web-Browser in arbeit

Was ist nicht implementiert

Wie man Menuet für PPP konfiguriert

Wie man Menuet für Ethernet konfiguriert

Als erstes benötigst du eine Ethernetkarte die unterstützt wird. Wenn du unsicher bist, welche Hardware du hast, versuche den Stack zu konfigurieren. Wenn deine Hardware unterstützt wird, wird sie gefunden und aktiviert.

Die ARP Tabelle einstellen

Menuets ARP Tabelle wird dynamisch kreiert und aufrechterhalten; Du kann sehen mit welche Hosts Menuet kommuniziert hat, indem du die ARPSTAT Anwendung startest.

Ethernet aktivieren

Der Stack läuft nun, indem du testest ob Menuet von einem entfernten Host anpingen kannst.

Die einfachste Art zwei PC's miteinander zu verbinden, ist ein 'Null Modem' Ethernet Kabel zu verwenden. Sie können in PC-Geschäften gekauft werden, aber sind auch einfach selber zu machen. Details findet man im Internet. Suche bei Google nach 'Ethernet Cross Over Cable' oder ähnlichem.

Wie man TCP/IP lokal, ohne Netzwerk nutzt

Menuet unterstützt eine Form von Local Loopbacks, dass bedeutet das Anwendungen am selben PC untereinander über Sockets kommunizieren können, als wären sie auf unterschiedlichen Rechnern. Um zu einer Anwendungen auf der selben Maschine zu verbinden, spezifiziere die lokale IP-Adresse als Ziel-Adresse. Du brauchst nicht den Stack für Ethernet konfigurieren; Local Loopback läuft ohne Netzwerk-Hardware. Das ist hervorragend für die Entwicklung und für Tests.

Interface für Anwendungsprogrammierung

Der Entwickler kann auf den Stack über Interrupt 0x40, Funktion 53 erreichen. Die Datei TFTPC.ASM gibt ein gutes Beispiel wie man das Programmierungs- interface nutzt (zumindest für UDP), aber da Netzwerkkommunikation komplex ist, werde ich einen Überblick geben.

Sockets

Anwendungen verbinden sich miteinander und tauschen Informationen untereinander aus, diesen Mechanismus nennt man 'Socket'. Sockets sind End-Punkte der Kommunikation; Du brauchst einen je Anwendung um zu kommunizieren.

Sockets zu benutzen ist in etwa so, als wenn man Dateien auf einem Betriebs- system benutzt; Du kannst Sie öffnen, lesen und schreiben und dann schließen. Das einzige was das leben etwas komplizierter macht ist, das ungleich mit einer Datei, du etwas intelligentes auf der anderen Seite hast (welches z.B. nicht geschlossen werden will, aber du!)

Lasst uns zuerst auf die Terminologie gucken, bevor wir weiter machen.

Socket Ein einzigartiger Identifizierer der von der Anwendung genutzt wird um zu kommunizieren.
Lokaler Port Eine Nummer welches diese Anwendung auf dem lokalen Rechner identifiziert. Ports sind ein Weg um mehreren Anwendungen zu erlauben miteinander zu kommunizieren, ohne dass die Daten durcheinander kommen. (Die technische Bezeichnung ist 'Multiplex'). Port Nummern sind 16Bit.
Remote Port Eine Nummer die die Anwendung auf einem entfernten Rechner identifiziert mit der wir kommunizieren. Für den entfernten Rechner ist das der 'Lokale Port'. Port Nummern sind 16Bit.
IP-Adresse eine 32Bit Nummer die den entfernten Rechner identifiziert mit dem wir kommunizieren.
Passiv Gibt den Modus an wie ein Socket geöffnet wird; Wenn man im Passiv-Modus öffnet, wartet der Lokale PC auf eine ankommende Verbindung.
Aktiv Gibt den Modus an wie ein Socket geöffnet wird; Wenn man im Aktiv-Modus öffnet, wird der Lokale PC versuchen eine Verbindung zu einem entfernten PC herzustellen.

Wenn du zu einem Socket an einem entfernten PC verbindest, benötigst du mehr als nur die IP-Adresse, sonst weiß der entfernte Stack nicht zu welcher Anwendung es deine Daten senden sollte. Du musst die Adresse vollständig definieren, was bedeutet dass du die IP-Adresse und die Port Nummer spezifizieren musst. Das wird wie folgt geschrieben

192.168.1.10:80 ;verbinden über Port 80 mit der Maschine 192.168.1.10

Port Nummern sind wichtig. Einige sind 'bekannt' und bieten Zugriff zu allgemeinen Anwendungen. Zum Beispiel Port 80 wird von HTTP-Servern benutzt; Das ist die Art eine Verbindung mit einem Webserver aufzubauen, ohne wissen zu müssen auf welcher Port Nummer die Anwendung 'hört'.

Das bringt mich auf den Weg, in welchen du Sockets öffnest; Wie ich früher schon sagte gibt es zwei Moden, Passiv und Aktiv. Ein Web-Browser sollte einen aktiven Socket öffnen, weil es versucht zu einem bestimmten Rechner zu verbinden.

Zugriff zum Programmierinterface

Der Entwickler hat über den Interrupt 0x40, Funktion 53 Zugriff auf die Stack-Funktionen. Einige Funktionen sind über die Funktion 52 zu erreichen, aber diese sind hauptsächlich für die Stack-Konfiguration. Hier ist eine Zusammenfassung der Funktionen und der Parameter-Definitionen, die du vielleicht brauchst.

Die Lokale IP-Adresse bekommen

eax = 52
ebx = 1
IP-Adress wird auf eax zurückgegeben (in Internet Byte Order)

zur Stack-Eingabeschlange schreiben

eax = 52
ebx = 6
edx = Anzahl der zu schreibenden Bytes
esi = Zeiger auf Daten (im Anwendungsbereich)
Als Rückgabewert, eax bekommt 0 wenn alles OK ist oder 0xFFFFFFFF für einen Fehler. Dieses Interface ist nur für langsame Netzwerktreiber (PPP, SLIP)

Daten von der Netzwerkausgabeschlange lesen

eax = 52
ebx = 8
esi = Zeiger auf Daten (im Anwendungsbereich)
Als Rückgabewert, eax bekommt die Anzahl der übertragenen Bytes.
Dieses Interface ist nur für langsame Netzwerktreiber (PPP, SLIP)

einen UDP-Socket öffnen

eax = 53
ebx = 0
ecx = Localer Port
edx = Remote Port
esi = Remote IP-Adresse (in Internet Byte Order)
Die Socket Nummer die alloziert wurde wird in eax zurückgegeben.
Ein Rückgabewert von 0xFFFFFFFF bedeutet das kein Socket geöffnet werden konnte.

einen TCP-Socket öffnen

eax = 53
ebx = 5
ecx = Localer Port
edx = Remote Port
esi = Remote IP-Adresse (in Internet Byte Order)
edi = Modus : SOCKET_PASSIVE oder SOCKET_ACTIVE (in stack.inc definiert)
Die allozierte Socket Nummer wird in eax zurückgegeben.
Ein Rückgabewert von 0xFFFFFFFF bedeutet das kein Socket geöffnet werden konnte.

Einen Socket schließen (nur UDP)

eax = 53
ebx = 1
ecx = Socket Nummer
Als Rückgabewert, eax erhält 0 wenn alles OK oder 0xFFFFFFFF für einen Fehler.

Einen Socket schließen (nur TCP)

eax = 53
ebx = 8
ecx = Socket Nummer
Als Rückgabewert, eax erhält 0 wenn alles OK oder 0xFFFFFFFF für einen Fehler.

Socket abfragen

eax = 53
ebx = 2
ecx = Socket Nummer
Als Rückgabewert, eax erhält die Anzahl der Bytes im Empfangspuffer.

Socket-Daten lesen

eax = 53
ebx = 3
ecx = Socket Nummer
Als Rückgabewert, eax erhält die Anzahl der restlichen Bytes, bl erhält ein Daten-Byte.

Socket schreiben (nur UDP)

eax = 53
ebx = 4
ecx = Socket Nummer
edx = Anzahl der zu schreibenden Bytes
esi = zeiger auf Daten (im Anwendungsbereich)
Als Rückgabewert, eax erhält 0 für alles OK oder 0xFFFFFFFF für einen Fehler.

Socket-Status zurückgeben (nur TCP)

eax = 53
ebx = 6
ecx = Socket Nummer
Als Rückgabewert, eax erhält den TCP-Status des Sockets.
Diese Funktion kann genutzt werden um herrauszufinden wann ein Socket mit einem anderen Socket verbunden ist - Daten können nicht zu einem Socket geschrieben werden bis die Verbindung aufgebaut ist (TCB_ESTABLISHED).
Die Statusse in dem ein Socket sein kann, sind in stack.inc als TCB_ definiert.

Socket schreiben (nur TCP)

eax = 53
ebx = 7
ecx = Socket Nummer
edx = Anzahl der zu schreibenden Bytes
esi = Zeiger auf Daten (im Anwendungsbereich)
Als Rückgabewert, eax erhält 0 für alles OK oder 0xFFFFFFFF für einen Fehler.

Port-Nummer checken

eax = 53
ebx = 9
ecx = Port Nummer
Diese Funktion wird benutzt um herrauszufinden ob eine Port-Nummer von einem Socket als Lokale Port-Nummer in Benutzung ist. Lokale Port-Nummern sind normalerweise einzigartig.

Als Rückgabewert, eax ist 1 wenn die Port-Nummer nicht in Benutzung ist, ansonsten 0.

Einen TCP-Socket in Menuet öffnen

Es gibt zwei Wege einen Socket zu öffnen - Passiv oder Aktiv.

Bei einer Passiven Verbindung 'hört' deine Anwendung nach ankommenden anfragen von einer entfernten Anwendung. Typerweise wird das getan, wenn du eine Server-Anwendung implementierst die es erlaubt jede andere Anwendung zu ihr zu verbinden. Du wirst eine 'bekannte' lokale Port- Nummer auswählen, wie 80 für Web-Server. Du wirst die Remote IP und die Remote Port-Nummer als 0 belassen, was bedeutet, dass jede entfernte Anwendung verbinden kann.

Wenn erstmal ein Socket geöffnet wurde, wirst du auf eine einkommende Verbindung warten bevor du etwas tun kannst. Dies kann einmal über den Socket-Status für TCB_ESTABLISHED gecheckt werden oder man wartet auf Daten die im Empfangspuffer landen.

Bei einer Aktiven Verbindung, baust du eine Verbindung zu einem spezifizierten Remote-Port auf. Die Parameter für die Remote-IP und den Remote-Port müssen mit nicht-Null-Werten gefüllt sein (zu wem soll man sich ansonsten verbinden?).
Du musst außerdem ein einzigartige lokale Port-Nummer spezifizieren, so dass dich die entfernte Anwendung eindeutig identifizieren kann - schließlich gibt es vielleicht einige Anwendungen auf deiner Maschine, die zum selben entfernten Rechner verbunden sind. Siehe weiter unten wie man eine eindeutige Port-Nummer findet.

Wie man eine unbenutzte lokale Port-Nummer findet

Normalerweise wenn du eine Aktive Verbindung zu einem entfernten Socket herstellst, willst du eine eindeutige lokale Port-Nummer auswählen. lokale Port-Nummer beginnen normalerweise bei 1000; Der folgende Code sollte benutzt werden um eine unbenutzte Port- Nummer zu erhalten bevor man einen offenen Socket wählt.

mov ecx, 1000 ;localer Port beginnt bei 1000

getlp:
inc ecx
push ecx
mov eax, 53
mov ebx, 9
int 0x40
pop ecx
cmp eax, 0 ;ist dieser locale Port in Benutzung?
jz getlp ;Ja - dann den nächsten

;ecx enthält eine freie Lokale Port-Nummer

Daten an einen Socket schreiben

Es sind zwei Funktionen Verfügbar, jenachdem ob der Socket für das TCP- oder UDP-Protokoll geöffnet wurde; Die Aufrufparameter sind nichts desto trotz dieselben. Wenn der Socket für TCP geöffnet wurde, benutze die Status-Funktion um eine Verbindung zu wählen - Daten können nicht geschrieben werden, solange ein anderer Socket zu ihm verbunden ist, Der Status des Sockets steht in TCB_ESTABLISHED.

Wenn du Daten schreibst, werden die Ergebnisse des Aufrufs in einem einzelnen IP-Paket erstellt und gesendet. Deshalb ist die Anwendung dafür Verantwortlich für die größe der gesendeten Pakete. Halte die Paketgröße unter 768 Bytes. Wenn du ein Terminal Programm wie Telnet schreibst, möchtest du vielleicht ein Paket für jeden Tastenanschlag senden (ineffizient) oder benutze einen Timer um Daten periodisch zu senden (z.B. jede Sekunde).

Daten vom Socket lesen

Es gibt eine Funktion um Daten vom Empfangspuffer des Sockets zu lesen. Diese Funktion holt sich immer ein Byte. Du kannst du Poll-Funktion nutzen um den Empfangspuffer auf Daten zu testen.

Einen Socket schließen

Rufe einfach die dazugehörige Funktion auf - es gibt eine für TCP und eine andere für UDP. Wenn du einen TCP-Socket schließt, vergiss nicht, dass das andere Ende vielleicht weiter Daten senden könnte, so dass der Socket für einige Sekunden nach deinem Aufruf Aktiv sein könnte.


Wenn du irgendwelche Fragen oder Vorschläge zur Verbesserung dieses Dokumentes hast, kontaktiere mich bitte unter menuetos[@]menuetos[.]de.