II. Questioni e preferenze
In questa sezione cerchiamo di presentare ciascuna delle diverse questioni sollevate nei recenti NWG/RFC e in conversazioni private e, per ogni questione, suggeriamo una risposta o una linea di condotta. In molti casi buone idee vengono respinte perché, a nostro giudizio, dovrebbero essere incorporate a un livello diverso.
A. Doppio riempimento
Come spiega il rapporto BBN #1822, il lato Imp dell'interfaccia Host-Imp concatena un 1 seguito da zero o più 0 per completare un messaggio fino a un confine di parola dell'Imp preservandone al tempo stesso la lunghezza. Inoltre, il lato Host dell'interfaccia Imp-Host estende un messaggio con degli 0 per completarlo fino a un confine di parola dell'Host.
Il meccanismo di BBN funziona bene se l'Host mittente vuole inviare un numero intero di parole, oppure se l'hardware dell'Host mittente è in grado di inviare parole parziali. Tuttavia, nel caso in cui l'Host mittente voglia inviare un messaggio di lunghezza irregolare e il suo hardware sia in grado di inviare soltanto messaggi multipli di una parola, è necessaria qualche convenzione aggiuntiva.
Una delle soluzioni più semplici consiste nel modificare il lato Imp dell'interfaccia Host-Imp in modo che accodi soltanto degli 0. Ciò significherebbe che il software dell'Host dovrebbe fornire l'1 finale. BBN ha respinto la modifica a causa di una comprensibile forte avversione verso le modifiche hardware. È stato anche suggerito che una patch di cinque istruzioni al programma dell'Imp eliminerebbe l'1 fornito dall'interfaccia, ma anche questa è stata respinta, con la nuova motivazione che sembrava più sicuro affidarsi soltanto all'hardware dell'Host per segnalare la fine del messaggio, e non dipendere affatto dal software dell'Host.
Sono disponibili anche altre due soluzioni. Una è il "doppio riempimento", in base al quale l'Host mittente fornisce 10* e anche la rete fornisce 10*. In ingresso, l'Host ricevente elimina quindi il 10* 10* finale. L'altra soluzione consiste nell'utilizzare la marcatura. La marcatura è una stringa della forma 0*1 inserita tra l'intestazione e il testo di un messaggio. Lo scopo originario della marcatura era estendere l'intestazione in modo che l'Host mittente potesse iniziare il proprio testo su un confine di parola. È anche possibile usare la marcatura per espandere un messaggio in modo che esso termini su un confine di parola.
Si noti che il doppio riempimento potrebbe sostituire del tutto la marcatura, facendo iniziare il testo a ridosso dell'intestazione. Per le macchine a 32 bit questo è comodo e la marcatura no, mentre per altre lunghezze, in particolare per le macchine a 36 bit, la marcatura è molto più comoda del doppio riempimento.
Non abbiamo una forte preferenza, in parte perché siamo in grado di inviare frammenti di parola. Shoshani e altri, nell'NWG/RFC #44, affermano che regolare la marcatura non causa loro alcun problema, e dispongono di una macchina a 32 bit. Poiché l'idea della marcatura è accettata da tempo, suggeriamo di non usare il doppio riempimento e di usare la marcatura per regolare la lunghezza di un messaggio. Osserviamo che, se BBN dovesse mai eliminare l'1 dal riempimento hardware, sul lato di invio sarebbe necessaria soltanto una modifica minima al software dell'Host.
Una soluzione molto più elegante (e più costosa) è stata suggerita da W. Sutherland. Egli ha suggerito che le interfacce Host/Imp siano abbastanza intelligenti da eliminare il riempimento o la marcatura e che possano perfino analizzare il messaggio in ingresso.
B. Riconnessione
Una folta schiera di esperti di reti ci ha criticato duramente per aver incluso la riconnessione dinamica nel protocollo. Abbiamo pensato che potesse essere interessante raccontare come si è arrivati a includerla.
Dopo aver riflettuto per un po' sulle connessioni e sui loro usi, ci siamo chiesti come il meccanismo delle connessioni si confrontasse con le forme esistenti di comunicazione tra processi all'interno di un Host. Due aspetti sono di interesse: quali formalismi sono stati presentati in letteratura e quali meccanismi sono in uso. I formalismi sono interessanti perché portano a implementazioni uniformi e a una progettazione parsimoniosa. I meccanismi esistenti sono interessanti perché indicano quali problemi occorre risolvere e talvolta suggeriscono quale potrebbe essere un formalismo appropriato. In particolare, abbiamo notato che i meccanismi per collegare una console al logger al momento della connessione telefonica, i meccanismi per creare un job e i meccanismi per passare una console tra i vari processi all'interno di un job tendono a essere altamente idiosincratici e distinti da tutte le altre strutture e meccanismi di un sistema operativo.
Per quanto riguarda la letteratura, sembra esserci un'unica idea con diverse varianti, cioè che i processi debbano condividere una parte dei propri spazi di indirizzamento e risvegliarsi a vicenda in modo cooperativo. I semafori e i canali di eventi sono comode estensioni dei segnali di risveglio, ma lo scopo è sostanzialmente lo stesso. (I canali di eventi potrebbero probabilmente funzionare come connessioni, ma ciò non sembra rientrare nel loro uso previsto. Nei sistemi piccoli, l'efficienza e la capacità dei canali di eventi sono inversamente correlate.)
Per quanto riguarda le implementazioni esistenti, osserviamo che diversi sistemi consentono a un processo di apparire come un file a un altro processo. Alcuni sistemi, ad esempio l'SDS-940 dell'SRI, impongono una relazione master/slave tra due processi così collegati, mentre altri sistemi prevedono una relazione paritaria, ad esempio il sistema PDP-6 del gruppo AI del MAC. Il sistema PDP-6 ha anche una funzione grazie alla quale un processo superiore può "circondare" un processo inferiore con una mappatura da nomi di dispositivi e file ad altri nomi di dispositivi e file. Le console hanno quasi la stessa semantica dei file, per cui è del tutto ragionevole che un processo inferiore creda di comunicare con la console mentre in realtà comunica con un altro processo.
La somiglianza tra le connessioni di rete e le connessioni sequenziali esistenti tra processi avvalora la nostra convinzione che le connessioni di rete siano probabilmente la struttura corretta per usare la rete. Inoltre, la struttura è sufficientemente pulita e compatibile con un numero sufficiente di macchine da poter passare per un formalismo o una teoria, almeno nella misura delle altre forme di comunicazione tra processi presentate in letteratura.
Qualsiasi nuovo formalismo, a nostro avviso, deve superare almeno le due prove seguenti:
-
Quali problemi aperti risolve?
-
È chiuso rispetto a tutte le operazioni?
Nel caso delle connessioni di rete, i candidati per la prima sono quelli indicati sopra, cioè tutte le operazioni che comportano il collegamento di una console a un job o a un processo. Sono di interesse anche la modellazione dei dispositivi sequenziali come le unità a nastro, le stampanti e i lettori di schede, e la modellazione dei relativi sistemi di bufferizzazione (spooling, symbiont).
La seconda domanda riguarda la chiusura. Nell'applicare il formalismo delle connessioni alle procedure di connessione telefonica e di login, abbiamo sentito la necessità di includere una qualche forma di commutazione o riconnessione, e una forma estremamente blanda è presentata in un articolo per la SJCC, che è anche l'NWG/RFC #33. Questa forma blanda consente soltanto la sostituzione degli AEN, e anche in quel caso solo al momento dell'instaurazione della connessione. Tuttavia, è esperienza comune che, se un'operazione ha una definizione naturale su un dominio esteso, prima o poi diventa necessario, o almeno desiderabile, estenderne la definizione. Abbiamo quindi considerato le seguenti estensioni:
-
Commutazione verso qualsiasi altro socket, eventualmente su un altro Host.
-
Commutazione anche dopo che il flusso di dati è iniziato.
Esiste perfino qualche precedente che fa ritenere utili queste estensioni. In una certa visione di un sistema operativo, tutte le linee telefoniche disponibili appartengono a un processo attivo noto come logger. Il logger risponde alle chiamate, filtra gli utenti e crea job e processi. Una delle caratteristiche della maggior parte delle apparecchiature di risposta telefonica è che molte linee possono servire lo stesso numero di telefono, utilizzando un blocco di numeri consecutivi e un sistema di risposta a rotazione. Nella nostra ricerca di modelli accurati dei sistemi reali, volevamo poter fornire un servizio equivalente agli utenti della rete, cioè questi dovrebbero poter chiamare un unico numero pubblicizzato ed essere collegati al logger. Si stabilisce così un argomento prima facie a favore della commutazione.
Vediamo poi che, dopo che il logger ha interrogato un potenziale utente, deve collegarlo a un job appena creato. Il flusso di dati tra l'utente e il logger è già iniziato, per cui il controllo di flusso deve essere integrato con la commutazione se non si vogliono perdere o alterare i dati in transito.
Per quanto riguarda la commutazione tra Host, è facile immaginare un servizio di utilità distribuito in tutta la rete che passi le connessioni da un socket all'altro all'insaputa dell'utente. Inoltre, ciò è simile ai sistemi telefonici più sofisticati, ai servizi standard degli operatori delle compagnie telefoniche e ai sistemi privati distribuiti.
Queste considerazioni ci hanno portato a studiare la possibilità di trovare un unico tipo di riconnessione che fornisse una base per tutti i modelli noti. L'algoritmo non è venuto facilmente, probabilmente per la nostra inesperienza con la teoria degli automi a stati finiti, ma alla fine abbiamo prodotto l'algoritmo presentato nell'NWG/RFC #36. Poco tempo dopo, Bill Crowther ha prodotto un algoritmo equivalente che adotta un approccio alternativo alle race condition.
Gli esperti di reti sembrano avere una di due reazioni. O era elegante e (forse ipso facto) utile, oppure era complesso e (di nuovo forse ipso facto) superfluo. Il secondo gruppo si è fatto sentire molto di più e siamo stati messi sulla difensiva, costretti ad ammettere che la riconnessione dinamica era soltanto
-
elegante
-
utile per il login e il passaggio della console
In risposta alle critiche insistenti, abbiamo apportato la seguente modifica al protocollo. Invece di chiamare il socket <O,H,O> per effettuare il login, i socket della forma <U,H,O> e <U,H,1> sono rispettivamente i socket di input e di output di una copia del logger oppure, se è stato avviato un job con l'id utente U, questi socket sono i socket della console. Il protocollo di login consiste quindi nell'avviare una connessione verso <U,H,O> e <U,H,1>. Se l'utente U non è in uso, risponderà una copia del logger che interrogherà il chiamante. Se l'id utente U è in uso, la chiamata sarà rifiutata. Questa modifica è stata suggerita di recente da Barry Wessler. (Anche altri avevano suggerito questa modifica molto prima, ma allora l'avevamo respinta.)
Il logger può esigere che il chiamante appartenga alla stessa rete virtuale, cioè che il chiamante abbia l'id utente U su qualche altro Host, oppure può esigere che l'utente fornisca una password corrispondente all'id utente U, oppure può esigere entrambe le cose. Alcuni sistemi potrebbero perfino scegliere di consentire a chiunque di effettuare il login con qualsiasi id utente.
Dopo il login, gli AEN 0 e 1 restano gli AEN della console. Ogni sistema dispone presumibilmente di meccanismi per passare la console, e questi verrebbero estesi per conoscere gli AEN 0 e 1 per gli utenti della rete. Il passaggio della console è quindi una questione di riconnessione dei socket alle porte e avviene all'interno dell'Host, senza coinvolgere la rete.
In conversazioni con Meyer e Skinner dopo la ricezione dell'NWG/RFC #46, essi hanno suggerito uno schema di login diverso sia da quello di Meyer sia dal nostro descritto nella sezione precedente. Il loro nuovo schema ci è sembrato un po' migliore e attendiamo con interesse la loro prossima nota.
Si concorda generalmente che il login debba essere di "terzo livello", cioè al di sopra del livello NCP. Cominciamo a essere indifferenti riguardo ai particolari schemi di login: tutti sembrano andare bene e nessuno ci colpisce granché. Suggeriamo di provarne diversi. Modificare la procedura di login locale comporta naturalmente un certo onere, ma riteniamo che gestire procedure di login diverse non imponga ulteriori difficoltà. Questo perché le sequenze di testo e le convenzioni sulle interruzioni sono così eterogenee che l'onere aggiuntivo di seguire, ad esempio, il nostro schema sul nostro sistema e quello di Meyer su Multics è minimo.
Siamo d'accordo che la riconnessione non debba essere richiesta nel protocollo iniziale, e la offriremo in seguito come strumento facoltativo e sperimentale. Inoltre, vorremmo lasciare agli atti la previsione che le funzioni di riconnessione generale diventeranno utili e forniranno un quadro unificante per le strutture dei sistemi operativi oggi ad hoc.
C. Disaccoppiamento di connessioni e link
Bill Crowther (BBN) e Steve Wolfe (UCLA) hanno suggerito, indipendentemente l'uno dall'altro, che i link non vengano assegnati a connessioni particolari. Suggeriscono invece di includere il socket di destinazione come parte del testo del messaggio e di inviare poi i messaggi su un qualsiasi link non bloccato.
Abbiamo discusso brevemente questa questione nell'NWG/RFC #37 e riteniamo che esistano ancora argomenti a favore di entrambe le soluzioni. Con l'attuale enfasi sulla semplicità, sulla velocità e su requisiti di memoria ridotti, sembra più efficiente lasciare accoppiati link e connessioni. Pertanto raccomandiamo questa soluzione.
D. Segnalazione degli errori
Come osservato da J. Heafner ed E. Harslem della RAND, è importante trattare gli errori che potrebbero verificarsi. Una buona filosofia è proteggersi da qualsiasi input che distrugga la coerenza della base di dati dell'NCP.
La formulazione specifica del comando di errore data da Heafner e Harslem nell'NWG/RFC #40 e da Meyer nell'NWG/RFC #46 sembra ragionevole e ne raccomandiamo l'adozione. Sono tuttavia opportune alcune osservazioni.
Occorre distinguere tra gli errori di risorse e gli altri tipi di errore. Gli errori di risorse sono semplicemente il rilevamento di condizioni di sovraccarico. Le condizioni di sovraccarico sono ben definite e valide, anche se forse indesiderabili. Gli altri tipi di errore riflettono software o hardware difettosi. Riteniamo che gli errori di risorse non debbano essere gestiti con meccanismi di errore, ma con meccanismi specifici del problema. Così il comando <CLS> può essere emesso quando non c'è più spazio per conservare gli <RFC> in attesa. Il protocollo di controllo di flusso è progettato unicamente per gestire il sovraccarico dei buffer.
Per quanto riguarda gli errori veri e propri, non siamo sicuri di quale sia il valore del comando <ERR> per il destinatario. Presumibilmente il suo NCP è guasto, e bombardarlo di comandi di errore potrebbe soltanto aggravare il problema. Raccomandiamo pertanto che la generazione degli errori sia facoltativa, che tutti gli errori vengano registrati localmente in un file cronologico e che anche i comandi <ERR> ricevuti vengano registrati in un file cronologico. Per il momento non è specificata alcuna azione correttiva.
Nel breve tempo in cui la rete è stata attiva all'UCLA, ci siamo convinti che la rete stessa genererà pochissimi errori. Abbiamo osservato il personale di BBN eseguire il debug e il collaudo del programma dell'IMP, e ci è sembrato che la maggior parte degli errori influisse sulla temporizzazione e sul throughput piuttosto che sulla validità. Pertanto la maggior parte degli errori deriverà probabilmente da Host guasti e/o da NCP difettosi.
E. Verifica e segnalazione dello stato
Un prezioso ausilio al debug è poter ottenere informazioni su ciò che un NCP remoto ritiene stia accadendo. Un modo comodo per farlo è consentire agli NCP di inviare lo stato ogni volta che lo desiderano, ma far sì che lo facciano sempre quando ricevono una richiesta.
Poiché consideriamo questa funzione principalmente uno strumento di debug, suggeriamo di usare un link distinto, ad esempio il 255. Lo scopo è che l'elaborazione delle richieste di stato e la generazione dei messaggi di stato utilizzino il meno possibile i meccanismi normali. Suggeriamo quindi di usare il link 255 per inviare i comandi "richiesta di stato" e "lo stato è". Il formato segue il suggerimento a pagina 2 dell'NWG/RFC #40.
Il comando <ECO> di Meyer è facile da implementare e svolge la funzione più elementare di verificare se un NCP remoto è attivo. Suggeriamo che la lunghezza del comando <ECO> sia variabile, poiché in questo contesto i 48 bit non sembrano avere alcun significato. Inoltre, il valore di un interruttore binario (presumibilmente) a 8 bit non è chiaro, per cui raccomandiamo una coppia di comandi:
<ECO> <length> <text>
e
<ERP> <length> <text>
dove
<length> è di 8 bit.
Alla ricezione di un comando <ECO>, l'NCP risponderebbe in eco con il comando <ERP>.
F. Espansione e sperimentazione
Come Meyer giustamente osserva nell'NWG/RFC #46, il protocollo di rete è una struttura a livelli. Finora se ne distinguono tre.
-
Protocollo della rete IMP
-
Protocollo del programma di controllo della rete
-
Protocollo di livello utente speciale o di livello sottosistema
Quest'ultimo livello dovrebbe restare idiosincratico per ciascun Host (o perfino per ciascun utente). Il primo livello è ben specificato da BBN, e qui ci concentriamo sul livello 2. Vorremmo mantenere il livello 2 il più neutro e semplice possibile e, in particolare, concordiamo che il protocollo di login debba trovarsi il più possibile al livello 3.
Nonostante la semplicità e la lungimiranza, si presenteranno occasioni in cui il protocollo di livello 2 dovrà essere modificato o sottoposto a sperimentazione. Per consentire la sperimentazione e il cambiamento, raccomandiamo che alle connessioni regolari vengano assegnati soltanto i numeri di link da 2 a 31, mentre i restanti numeri di link, da 32 a 255, siano usati a scopo sperimentale. Abbiamo già suggerito di usare il link 255 per le richieste e le risposte di stato, e ciò è in armonia con la nostra visione degli aspetti sperimentali di tale funzione.
Raccomandiamo inoltre di usare per la sperimentazione i prefissi dei comandi di controllo a partire da 255 verso il basso.
Queste due convenzioni sono sufficienti, a nostro avviso, per consentire una comoda sperimentazione di nuovi protocolli tra qualsiasi sottoinsieme dei siti. Non siamo quindi favorevoli all'inclusione del suggerimento di Ancona nell'NWG/RFC #42 di un codice di tipo di dati del messaggio come primi otto bit del testo di un messaggio.
G. Multiplazione delle porte sui socket
Wolfe nell'NWG/RFC #38 e Shoshani e altri nell'NWG/RFC #44 suggeriscono che dovrebbe essere possibile collegare più di una porta a un socket. Sebbene tutti i nostri diagrammi e le nostre chiamate di sistema prototipiche abbiano mostrato una corrispondenza biunivoca tra socket e porte, si tratta strettamente di una questione di implementazione locale. Osserviamo che i socket formano uno spazio dei nomi esteso a tutta la rete, il cui unico scopo è fare da interfaccia tra le strutture idiosincratiche proprie di ciascun sistema operativo. I nostri riferimenti alle porte sono da intendersi soltanto come indicativi, e vanno ignorati se nessuna struttura interna vi corrisponde. La maggior parte dei sistemi ha comunque strutture di questo tipo, per cui continueremo a usarle a scopo illustrativo.
H. Eco, interruzioni e conversione di codice
1. Interruzioni
Avevamo l'impressione che tutti i sistemi operativi esaminassero l'input da tastiera alla ricerca di un carattere riservato da interpretare come segnale di interruzione. Tom Skinner ed Ed Meyer del MIT ci informano che le TTY modello 37 e l'IBM 2741 generano uno "spazio lungo" di 200-500 millisecondi, che viene rilevato dall'hardware del canale di I/O e passato al sistema operativo come interruzione. Lo "spazio lungo" non è un carattere: non ha un codice ASCII e non può essere generato da programma.
Più di un anno fa avevamo considerato il problema di simulare le interruzioni della console e avevamo respinto il comando di tipo <INT> perché non modellava correttamente nessun sistema a noi noto. Ora rivediamo la nostra posizione e raccomandiamo l'implementazione di una chiamata di sistema INTERRUPT e di un comando di controllo <INT>, come suggerito da Meyer nell'NWG/RFC #46.
Occorre rispettare due restrizioni della funzione di interruzione. In primo luogo, questa funzione non dovrebbe essere usata quando si comunica con sistemi che cercano caratteri di interruzione. In secondo luogo, le connessioni che non hanno natura di console probabilmente non dovrebbero avere interruzioni. Raccomandiamo che i sistemi seguano le proprie convenzioni e che, se arriva un <INT> per una connessione per la quale non dovrebbe arrivare, l'<INT> venga scartato ed eventualmente restituito come errore.
2. Eco e conversione di codice
Riteniamo che ciascun sito debba mantenere la propria attuale politica di eco e che la conversione di codice debba essere effettuata dal processo utilizzatore. La standardizzazione in quest'area dovrebbe attendere ulteriori sviluppi.
Il suggerimento di Ancona di un trasduttore di front-end guidato da tabelle sembra la soluzione giusta, ma riteniamo che tali tecniche facciano parte di una discussione più ampia che riguarda i linguaggi di livello superiore per la rete.
I. Funzioni di broadcast
Heafner e Harslem suggeriscono nell'NWG/RFC #39 una funzione di broadcast, cioè <TER> e <BDC>. Non comprendiamo appieno il valore di questa funzione e siamo quindi propensi a respingerla. Sospettiamo che ne comprenderemmo meglio il valore se avessimo più esperienza con OS/360. È probabilmente vero in generale che i siti che utilizzano OS/360 o sistemi simili troveranno meno pertinenti i nostri suggerimenti per il protocollo di rete rispetto ai siti che utilizzano sistemi a condivisione di tempo. Apprezzeremmo qualsiasi esposizione convincente sulla relazione tra OS/360 e i concetti e le ipotesi alla base del protocollo di rete.
J. Numeri di istanza
Meyer, nell'NWG/RFC #46, suggerisce di estendere il socket per includere un codice di istanza che identifichi il processo collegato al socket. Abbiamo organizzato le cose con cura in modo che i processi fossero indistinguibili. Lo abbiamo fatto nella convinzione che, sia sul piano formale sia su quello pratico, se un calcolo venga eseguito da uno o da molti processi riguardi soltanto l'interno di un Host. Riteniamo quindi che tutti i processi di un job debbano cooperare nell'assegnazione degli AEN. Se un sistema operativo dispone di funzioni per passare una console da un processo all'altro all'interno di un job, queste si integrano bene con l'attuale protocollo di rete, anche all'interno del protocollo di riconnessione; i numeri di istanza, invece, interferiscono con una procedura di questo tipo.
Suggeriamo che questa questione venga discussa a fondo, perché riguarda la filosofia di base dei socket e delle connessioni. Per il momento raccomandiamo numeri di socket a 40 bit senza codici di istanza.
K. Gli AEN
Nessuno, noi compresi, è particolarmente soddisfatto del nostro nome AEN per gli 8 bit di ordine inferiore del socket. Abbiamo scartato socket_number e siamo altrettanto insoddisfatti del socket_code di Meyer. La parola socket non dovrebbe essere usata come parte del nome del campo, e sollecitiamo suggerimenti.