III - Netzsteuerungsprogramm
Jeder HOST implementiert ein Modul namens Netzsteuerungsprogramm (NCP), das die gesamte Netzwerkkommunikation dieses HOST steuert. Das Netz der NCPs bildet ein verteiltes Kommunikationssystem, das Kommunikationswege zwischen einzelnen Prozessen implementiert. Die Protokollfragen des NCP betreffen: (i) die Definition dieser Kommunikationswege und (ii) ein Verfahren zur Koordinierung des verteilten NCP-Systems bei der Aufrechterhaltung dieser Kommunikationswege. Diese werden im Folgenden erörtert.
Sockets
Die Kommunikation zwischen zwei Prozessen erfolgt über eine Simplex-Verbindung zwischen zwei Sockets: einem Send-Socket, der an einen Prozess angeschlossen ist, und einem Empfangs-Socket, der an einen anderen Prozess angeschlossen ist. Sockets haben die folgenden Merkmale:
Socket-Bezeichner - Ein Socket-Bezeichner wird im gesamten Netz verwendet, um einen Socket eindeutig zu identifizieren. Er besteht aus 48 Bit und hat die folgenden Bestandteile:
-
Benutzernummer (24 Bit) - Ein an einen Prozess angeschlossener Socket wird dadurch als zu diesem Prozess gehörend identifiziert, dass eine Benutzernummer aus 8 Bit "Heimat"-HOST-Code plus 16 Bit vom Heimat-HOST zugewiesenen Benutzercode verwendet wird. Diese Benutzernummer ist für alle Sockets gleich, die an irgendeinen seiner Prozesse in irgendeinem HOST angeschlossen sind.
-
Instanz-Tag (8 Bit) - Mehr als ein zu einem Benutzer gehörender Prozess kann gleichzeitig innerhalb eines einzigen HOST bestehen. Das Instanz-Tag identifiziert den bestimmten Prozess, zu dem ein Socket gehört. Der erste Prozess eines Benutzers auf einem HOST, der das Netz nutzt, erhält konventionsgemäß das Instanz-Tag = 0.
-
HOST-Nummer (8 Bit) - Dies ist der Code des HOST, auf dem der angeschlossene Prozess existiert.
-
Socket-Code (8 Bit) - Dieser Code sieht 128 Send- und 128 Empfangs-Sockets in jedem Prozess vor. Das niedrigstwertige Bit bestimmt, ob es sich um einen "Send"- (= 1) oder einen "Empfangs"-Socket (= 0) handelt.
Zustände von Sockets - Jeder Socket hat einen zugehörigen Zustand. Das NCP kann weitere Übergangszustände eines Sockets implementieren, doch die folgenden drei sind von begrifflicher Bedeutung.
-
Inaktiv - Es gibt gegenwärtig keinen Prozess, der dem NCP mitgeteilt hat, dass er diesen Socket abhören möchte. Kein anderer Prozess kann mit einem inaktiven Socket erfolgreich kommunizieren.
-
Offen - Ein Prozess hat zugestimmt, Ereignisse zu diesem Socket abzuhören, aber er ist noch nicht verbunden.
-
Verbunden - Dieser Socket ist gegenwärtig mit einem anderen Socket verbunden.
Socket-Ereigniswarteschlange - Für jeden offenen oder verbundenen Socket wird eine Warteschlange von Ereignissen geführt, die dem besitzenden Prozess offenbart werden sollen. Sie besteht aus einer chronologisch geordneten Liste bestimmter Ereignisse, die durch die Aktion eines oder mehrerer fremder Prozesse erzeugt werden, die diesen Socket zu verbinden oder zu trennen versuchen. Ein Eintrag in der Ereigniswarteschlange besteht aus der Ereignisart plus dem Bezeichner des betroffenen fremden Sockets. Die folgenden Ereignisarten sind definiert:
-
"request" - ein fremder Socket beantragt eine Verbindung. (wird nicht eingereiht, wenn der lokale Socket bereits verbunden ist)
-
"accept" - ein fremder Socket nimmt die beantragte Verbindung an.
-
"reject" - ein fremder Socket lehnt die beantragte Verbindung ab.
-
"close" - ein fremder Socket trennt eine bestehende Verbindung.
Ein "request"-Ereignis wird aus der Warteschlange entfernt, wenn es angenommen oder abgelehnt wird. Die anderen Ereignisse werden aus der Warteschlange entfernt, sobald sie dem besitzenden Prozess offenbart werden.
Manche Ereignisse sollen für den den Socket besitzenden Prozess transparent sein, und sie erzeugen keine Einträge in der Ereigniswarteschlange.
Obwohl eine Ereigniswarteschlange begrifflich unbegrenzt ist, erscheint es notwendig, ihrer Länge eine praktische Grenze zu setzen. Wenn die Ereigniswarteschlange eines Sockets voll ist, sollte jedes eintreffende Ereignis, das sie vergrößern würde, verworfen und das sendende NCP benachrichtigt werden (über den unten beschriebenen ERR-Befehl).
NCP-Steuerkommunikation
Das NCP-Netz koordiniert seine Tätigkeiten durch Steuerbefehle, die zwischen seinen einzelnen Komponenten ausgetauscht werden. Diese Befehle betreffen im Allgemeinen die Erzeugung und Handhabung von Socket-Verbindungen, die das den Befehl empfangende NCP steuert. Ein Steuerbefehl wird an ein bestimmtes NCP gerichtet, indem er als Nachricht über die Link-Nummer 1 (als Steuerlink bezeichnet) an dessen HOST gesendet wird; diese ist für diesen Zweck reserviert. Das IMP-Netz unterscheidet nicht zwischen diesen Nachrichten und regulären Datennachrichten, die Kommunikation über eine Socket-Verbindung realisieren.
Die folgenden NCP-Steuerbefehle sind definiert:
-
Verbindungsanforderung
RFC <local socket> <foreign socket> [<link no.>]Ein NCP richtet diesen Befehl an ein fremdes NCP, um den Aufbau einer Verbindung zwischen einem lokalen Socket und einem fremden Socket zu versuchen. Ist der fremde Socket offen, legt das fremde NCP ein "request"-Ereignis in die Ereigniswarteschlange des Sockets, damit es dem besitzenden Prozess offenbart wird. Nimmt der fremde Prozess an, so gibt das fremde NCP eine positive Bestätigung in Form eines weiteren RFC zurück. Es lehnt die Verbindung ab, indem es den CLS-Befehl ausgibt (siehe unten). Ein RFC wird automatisch abgelehnt, ohne den besitzenden Prozess zu befragen, wenn der fremde Socket nicht offen ist (inaktiv oder verbunden). Mehrere RFCs an denselben Socket werden in der Reihenfolge des Eingangs in seine Ereigniswarteschlange gestellt. Alle eingereihten RFCs werden vom NCP automatisch abgelehnt, sobald der besitzende Prozess beschließt, eine Verbindung anzunehmen. Das NCP, das den "Empfangs"-Socket des möglicherweise verbundenen Paares steuert, bestimmt eine Link-Nummer, über die Nachrichten fließen sollen.
-
Schließen einer Verbindung
CLS <local socket> <foreign socket>Ein NCP gibt diesen Netzwerkbefehl aus, um eine bestehende Verbindung zu trennen oder einen RFC negativ zu bestätigen. Es gibt ein mögliches Wettlaufproblem, wenn ein NCP einen lokalen Send-Socket schließt, da der CLS-Befehl das fremde NCP vor der letzten Nachricht über diese Socket-Verbindung erreichen kann. Dieses Wettlauf wird durch die Einhaltung zweier Grundsätze verhindert: (i) Ein CLS-Befehl für einen lokalen Send-Socket wird erst übertragen, wenn der RFNM für die letzte Nachricht an den fremden Socket zurückgekommen ist, und (ii) das fremde NCP verarbeitet alle eingehenden Nachrichten in der Reihenfolge des Eingangs.
-
Blockieren der Ausgabe über eine Verbindung
BLK <foreign send socket>Ein Prozess kann Daten über einen Empfangs-Socket langsamer lesen, als Nachrichten eintreffen, und daher können sich die Puffer des NCP zusetzen. Das NCP gibt diesen Befehl an ein fremdes NCP aus, um die weitere Übertragung über das Socket-Paar zu blockieren, bis der empfangende Prozess aufgeholt hat.
-
Fortsetzen der Ausgabe über eine blockierte Verbindung
RSM <foreign send socket>Ein NCP gibt diesen Befehl aus, um eine zuvor blockierte Verbindung zu entblockieren.
-
Unterbrechen des an eine Verbindung angeschlossenen Prozesses
INT <foreign socket>Der Empfang dieser Nachricht veranlasst das fremde NCP, den an <foreign socket> angeschlossenen fremden Prozess unverzüglich zu unterbrechen, wenn er mit einem lokalen Socket verbunden ist. Daten, die sich innerhalb des NCP-Netzes bereits über die unterbrochene Verbindung im Transit befinden, werden an den Ziel-Socket übertragen. Die Bedeutung von "Unterbrechung" ist, dass der Prozess seine laufende Ausführung unverzüglich abbricht und eine Standardprozedur ausführt. Diese Prozedur ist auf dieser Protokollebene nicht definiert.
-
Melden eines fehlerhaften Befehls an ein fremdes NCP
ERR <code> <command length> <command in error>Dieser Befehl dient dazu, unechte Netzwerkbefehle oder -nachrichten oder Überlastbedingungen zu melden, die die Verarbeitung des Befehls verhindern. <code> gibt die Fehlerart an. Wenn <code> einen fehlerhaften Netzwerkbefehl bezeichnet, so ist <command in error> dieser Befehl (ohne IMP-Kopf) und <command length> eine ganze Zahl, die seine Länge in Bit angibt. Wenn <code> eine fehlerhafte Nachricht bezeichnet, so enthält <command in error> nur die Link-Nummer, über die die fehlerhafte Nachricht übertragen wurde. (Dies weicht geringfügig von der Spezifikation in NWG/RFC 40 ab.)
-
Netzwerktestbefehl
ECO <48 bit code> <echo switch>Ein NCP kann die Qualität der Kommunikation zwischen ihm und einem fremden NCP prüfen, indem es an dieses einen ECO-Befehl mit einem beliebigen <48 bit code> (von derselben Länge wie ein Socket-Bezeichner) und <echo switch> 'on' richtet. Ein NCP, das einen solchen ECO-Befehl empfängt, sollte unverzüglich einen bestätigenden ECO mit demselben <48 bit code> und <echo switch> 'off' an das ursprüngliche NCP senden. Ein NCP bestätigt einen ECO mit <echo switch> 'off' nicht. Wir sind der Ansicht, dass dieser Befehl bei der anfänglichen Erprobung des gesamten Netzes eine beträchtliche Hilfe sein wird.
-
Leerbefehl
NOPEin NCP verwirft diesen Befehl bei Empfang.
Benutzerschnittstelle zum NCP
Das NCP jedes HOST besitzt eine Schnittstelle, über die ein lokaler Prozess das Netz unter der Kontrolle des NCP nutzen kann. Die genaue Spezifikation dieser Schnittstelle ist keine Frage des Netzwerkprotokolls, da jede Installation ihre eigene, auf ihre besonderen Erfordernisse zugeschnittene Schnittstelle haben wird. Die Protokollerfordernisse für die Benutzerschnittstelle zu einem NCP sind, dass sie alle beabsichtigten Netzwerkfunktionen und keine unzulässigen Privilegien bereitstellt. Beispiele für solche unzulässigen Privilegien sind die Fähigkeit, sich als ein anderer Prozess auszugeben, Kommunikation abzuhören, die nicht für sie bestimmt ist, oder das NCP dazu zu verleiten, unechte Netzwerkbefehle oder -nachrichten auszusenden.
Wir skizzieren hier eine Schnittstelle auf der Grundlage des Vorschlags von Carr, Crocker und Cerf, die ausreicht, das Netz vollständig zu nutzen. Obwohl diese bestimmte Menge von Aufrufen hauptsächlich der Veranschaulichung dient, zeigt sie die Arten der notwendigen Funktionen auf.
Die folgenden Aufrufe an das NCP stehen zur Verfügung:
-
LISTEN <my 8 bit socket code>
Der Benutzer öffnet diesen Socket und erzeugt damit eine leere Ereigniswarteschlange für ihn. Dieser LISTEN-Aufruf kann blockieren und auf das erste "request"-Ereignis warten, oder er kann unverzüglich zurückkehren.
-
INIT <my socket code> <foreign socket>
Der Benutzer versucht, <my socket> mit <foreign socket> zu verbinden. Das lokale NCP sendet einen RFC an das fremde NCP und beantragt damit die Erzeugung der Verbindung. Die zurückgegebene Bestätigung ist entweder ein RFC (Anforderung angenommen) oder ein CLS (Anforderung abgelehnt). Nach Wahl des Aufrufers blockiert der INIT-Aufruf auf dem erwarteten "accept"- oder "reject"-Ereignis, oder er kann unverzüglich zurückkehren, ohne zu warten. In diesem Fall muss der Benutzer zu einem späteren Zeitpunkt STATUS (siehe unten) aufrufen, um die Aktion des fremden NCP zu ermitteln. Wenn ein blockierter INIT-Aufruf zurückkehrt, wird das "accept"- oder "reject"-Ereignis aus der Ereigniswarteschlange entfernt.
-
STATUS <my socket code>
Dieser Aufruf meldet das früheste zuvor nicht gemeldete Ereignis in der Warteschlange von <my socket>. Der STATUS-Aufruf löscht das Ereignis aus der Warteschlange, wenn diese Ereignisart durch Offenbarung löschbar ist.
-
ACCEPT <my socket code>
Der Benutzer nimmt die Verbindung mit dem fremden Socket an, dessen "request"-Ereignis in der Ereigniswarteschlange für <my socket> am frühesten steht. Ein bestätigender RFC wird an den angenommenen fremden Socket gesendet, und das "request"-Ereignis wird aus der Ereigniswarteschlange gelöscht. Sollte ein weiteres "request"-Ereignis in der Warteschlange stehen, lehnt das NCP die Verbindung automatisch ab, indem es einen CLS-Befehl aussendet und das Ereignis löscht.
-
REJECT <my socket code>
Der Benutzer lehnt die Verbindung mit dem fremden Socket ab, dessen "request"-Ereignis in der Ereigniswarteschlange für <my socket> am frühesten steht. Das NCP sendet einen CLS-Befehl aus und löscht das "request"-Ereignis aus der Warteschlange.
-
CLOSE <my socket code>
Der Benutzer weist das NCP an, jede aktive Verbindung zu diesem Socket zu trennen und den Socket zu deaktivieren. Das NCP sendet einen CLS-Befehl an den fremden Socket, wenn eine Verbindung bestanden hat. Der Zustand des fremden Sockets wird ebenfalls geschlossen, sobald das "close"-Ereignis dem fremden Prozess offenbart wird.
-
INTERRUPT <my socket code>
Der Benutzer weist das NCP an, einen INT-Befehl an den mit <my socket> verbundenen fremden Socket auszusenden.
-
TRANSMIT <my socket code> <pointer> <nbits>
Der Benutzer möchte <nbits> an Daten in einen von <pointer> bezeichneten Bereich lesen (<my socket> ist Empfang) oder daraus schreiben (<my socket> ist Senden). Ein Schreibaufruf kehrt unverzüglich zurück, nachdem das NCP die Daten zum Senden einer Nachricht über die Verbindung eingereiht hat. Der Schreibaufruf blockiert nur, wenn die Verbindung blockiert ist oder das lokale NCP zu stark belastet ist, um die Anforderung unverzüglich zu verarbeiten. Über eine Verbindung zu übertragende Daten werden in eine oder mehrere IMP-Nachrichten mit einer Höchstlänge von 8095 Bit formatiert und über die im RFC, den das die Empfangsverbindung steuernde NCP gesendet hat, angegebene Link-Nummer an den fremden HOST übertragen. Ein "close"-Ereignis in der Ereigniswarteschlange für <my socket> wird durch die Wirkung von TRANSMIT offenbart. Ein Schreibaufruf offenbart das "close"-Ereignis unverzüglich. Ein Leseaufruf offenbart es, wenn alle Daten gelesen wurden.
Der Werdegang einer Verbindung aus Benutzersicht
Ein anschauliches Beispiel
Nehmen wir an, der Prozess 'a' auf HOST A möchte eine Verbindung mit dem Prozess 'b' auf HOST B aufbauen. Bevor Kommunikation stattfinden kann, müssen zwei Bedingungen erfüllt sein:
-
Prozess 'a' muss seinem NCP einen Socket im Socket-Raum von 'b' angeben können, mit dem er sich verbinden will.
-
Prozess 'b' muss diesen Socket bereits abhören (LISTEN).
1. Aufbau der Verbindung
-
Prozess 'b' führt LISTEN auf Socket 'Bb9' aus.
-
Prozess 'a' führt INIT von 'Bb9' auf sein 'Aa12' aus. Das NCP bei A erzeugt einen RFC, der die Link-Nummer = 47 angibt, die es aus seiner verfügbaren Link-Menge wählt. Dies ist der Link, über den es Nachrichten empfangen wird, wenn die Verbindung von Prozess 'b' angenommen (ACCEPT) wird.
-
Prozess 'b' wird über die INIT-Anforderung von A informiert. Er kann die Verbindung ablehnen (REJECT) (NCP B sendet einen CLS zurück) oder annehmen (ACCEPT) (NCP B sendet einen RFC zurück).
-
Wenn Prozess 'b' ACCEPT ausführt, stellt der bestätigende RFC die Verbindung her, und Nachrichten können nun fließen.
HOST A | HOST B
INITIATOR | ACCEPTOR
PROCESS 'a' | PROCESS 'b'
|
|
| a. LISTEN 'socket code 9'
|
|
b. INIT 'socket code 12' 'Bb9' |
RFC 'AA12' 'Bb9' 'link 47' ==========>
|
| c. ACCEPT 'socket code 9'
| RFC 'Bb9' 'Aa12'
|
| d. TRANSMIT 'send buffer' 'len'
| 'socket 9'
<============== IMP message 'link 47' 'send buffer'
|
e. TRANSMIT 'rec buffer' 'length'
'socket 12' ============>
|
| f. CLOSE 'socket code 9'
|
last RFNM ===>
<============== CLS 'Bb9' 'Aa12'
closes socket 'Aa12' |
|
Abbildung 2: Aufbau und Kommunikation über eine Socket-Verbindung
2. Senden von Nachrichten über eine Verbindung
-
Prozess 'b' gibt einen TRANSMIT-Aufruf aus, um Daten über die Verbindung zu senden. NCP B formatiert diese in eine IMP-Nachricht und sendet sie mit der von A's RFC angegebenen Link-Nummer = 47 an NCP A.
-
NCP A empfängt die rohe Nachricht von NCP B mit der Link-Nummer = 47. NCP A verwendet diese Link-Nummer, um zu entscheiden, wer der beabsichtigte Empfänger ist, und legt die Nachricht in einem Puffer für den empfangenden Prozess ab.
-
Prozess 'a' kann zu einem beliebigen Zeitpunkt einen Leseaufruf (TRANSMIT) für Socket-Code 12 ausgeben. Der Leseaufruf blockiert, wenn keine Daten für den Socket ausstehen. Der Leseaufruf nimmt die angegebene Anzahl von Bits auf, die über Socket-Code 12 übertragen wurden, gegebenenfalls über eine IMP-Nachrichtengrenze hinweg. Die Grenzen der IMP-Nachrichten sind für den Leseaufruf unsichtbar.
-
Sollte Prozess 'b' Daten schneller über die Verbindung senden, als Prozess 'a' sie aufnimmt, kann NCP A einen BLK-Befehl an NCP B ausgeben, wenn sich A's Puffer zu füllen beginnen. Später, wenn Prozess 'a' aufgeholt hat, kann NCP A B über einen RSM-Befehl anweisen, die Übertragung fortzusetzen.
3. Prozess 'b' schließt die Verbindung
-
Prozess 'b' beschließt, die Verbindung zu schließen, und gibt den CLOSE-Aufruf an NCP B aus. Um Wettlaufprobleme zu vermeiden, wartet B auf den RFNM der vorangehenden Nachricht über diese Verbindung und sendet dann den CLS-Befehl an NCP A. Wenn der RFNM der CLS-Befehlsnachricht zurückkehrt, entfernt NCP B den Socket 'Bb9' aus seinen Tabellen, wodurch die Schließung an seinem Ende bewirkt und 'Bb9' deaktiviert wird.
-
Wegen der sequenziellen Verarbeitung innerhalb von NCP A ist gewährleistet, dass die letzte Nachricht an Socket 'Aa12' an einen Prozess gerichtet wurde, bevor der CLS von NCP B eintrifft. Bei Empfang des CLS von B markiert NCP A den Socket 'Aa12' als "close pending" und legt ein "close"-Ereignis in die Ereigniswarteschlange von 'Aa12'.
-
Prozess 'a' kann weiterhin Leseaufrufe für Socket 'Aa12' ausgeben, solange gepufferte Daten ausstehen. Wenn 'a' einen Leseaufruf ausgibt, nachdem der Puffer geleert wurde, wird das "close"-Ereignis offenbart, um 'a' über die Schließung zu informieren, und Socket 'Aa12' wird aus den Tabellen von NCP A entfernt.
4. Prozess 'a' schließt die Verbindung
-
Kehren wir zu Schritt 2 zurück und nehmen wir an, dass Prozess 'a' die Verbindung von seinem Ende aus schließen möchte. Es gibt kein Wettlaufproblem, da wir annehmen, dass 'a' nach Ausgabe eines CLOSE-Aufrufs keine Nachrichten mehr über diesen Socket lesen möchte.
-
Nehmen wir an, dass Prozess 'a' einen CLOSE-Aufruf für Socket 'Aa12' ausgibt. NCP A sendet unverzüglich einen CLS-Befehl an NCP B und markiert den Socket 'Aa12' als "close pending". Alle zum Lesen auf 'Aa12' gepufferten Daten werden verworfen. Damit verbleibende, bereits von Prozess 'b' auf dem Weg befindliche Nachrichten das IMP-Netz bis zu NCP A durchsickern und ohne Fehlermeldungen verworfen werden können, behält NCP A 'Aa12' für einen geeigneten Zeitraum nach Empfang des RFNM des CLS-Befehls in seinen Tabellen. Während dieses Zeitraums verwirft NCP A alle über die sich schließende Verbindung empfangenen Nachrichten. Nachdem diesen toten Nachrichten eine angemessene Zeit zum Eintreffen eingeräumt wurde, entfernt NCP A 'Aa12' aus seinen Tabellen, wodurch die Verbindung wirksam geschlossen und 'Aa12' deaktiviert wird. Weitere Nachrichten an Socket 'Aa12' führen dazu, dass NCP A ein ERR "erroneous command" an das ursprüngliche NCP sendet.
-
Wenn NCP B den CLS-Befehl empfängt, wird Socket 'Bb9' als "close pending" markiert, und das CLS-Ereignis wird in die Ereigniswarteschlange von 'Bb9' gelegt. Wenn Prozess 'b' das nächste Mal über diesen Socket schreiben möchte, wird das CLS-Ereignis offenbart, um ihn über die Schließung zu informieren, und Socket 'Bb9' wird aus den Tabellen von NCP B entfernt.