Manuale per la programmazione Tivoli Service Desk 6.0 Developer's Toolkit Script
Questo capitolo introduce i concetti fondamentali necessari per
utilizzare le istruzioni di estensione di rete TSD Script per
comunicare nella rete.
Il capitolo descrive, inoltre, concetti speciali di rete, istruzioni
e costanti TSD Script.
E' possibile utilizzare queste istruzioni TSD Script per
personalizzare il codice di origine per le applicazioni installate o
per creare un'applicazione personalizzata distribuita di TSD Script.
Sebbene questo capitolo tratti alcuni aspetti fondamentali dei principi della rete e del linguaggio di TSD Script, si presume che si conoscano già entrambe le aree. Se si sta modificando un'applicazione, potrebbe essere necessario lavorare con qualcuno che abbia personalizzato altre applicazioni o che abbia utilizzato TDS Script e Developer's Toolkit.
Le istruzioni incluse con il linguaggio TSD Script forniscono due tipi distinti di architetture di rete:
In questo capitolo, la descrizione dei servizi di rete TSD Script è applicabile, generalmente, a entrambe le architetture. Dove esistono differenze tra le architetture, esse vengono specificate.
Vengono utilizzati vari termini per descrivere le interazioni tra i computer su una rete. Sebbene essi possano essere già noti, vengono qui definiti nel contesto specifico del loro utilizzo con le estensioni di rete TSD Script.
La comunicazione bidirezionale si verifica quando due macchine si comportano l'una come client e l'altra come server. In altre parole, la macchina A (client) può richiedere alla macchina B (server) di eseguire qualche operazione. Allo stesso modo, la macchina B può invertire i ruoli e diventare client chiedendo alla macchina A di eseguire delle operazioni. Consultare anche la definizione di connessione inversa. Consultare peer-to-peer.
Un Client è un'applicazione che richiede un servizio da un server. Un esempio di client è una workstation su una rete che si connette a un server di file. La connessione viene iniziata dal client.
Una connessione è il collegamento logico tra un client e un server.
Un handler degli eventi è una funzione TSD Script speciale progettata per elaborare eventi asincroni. Gli handler degli eventi vengono eseguiti sul server per elaborare le richieste di rete per un servizio.
Ogni connessione ha un handle. Una handle contiene informazioni sulla macchina client e sul servizio fornito dal server.
Un server TSD Script è un processo TSD Script in esecuzione su un computer di rete che fornisce un servizio.
L'handler degli eventi locale è l'handler degli eventi che opera sulla macchina locale. Se un handler degli eventi soddisfa le richieste da una macchina diversa, quella macchina è un server.
Le istruzioni NETx o estensioni, sono le istruzioni TSD Script che incominciano con il prefisso NET. Queste istruzioni sono state create per consentire alle applicazioni TSD Script di comunicare in una rete.
Un ambiente peer-to-peer è un ambiente in cui una singola macchina può essere sia un client che un server.
La registrazione di un handler degli eventi associa l'handler all'origine degli eventi.
Una connessione inversa può essere stabilita in un ambiente peer-to-peer quando un server richiede a un client di eseguire un servizio invertendo effettivamente i ruoli di client e server. Per gestire questa comunicazione, viene stabilita una connessione inversa tra il server locale e il server remoto.
Il server è una macchina che fornisce un servizio al client. Un esempio di server è una stampante di rete.
Un servizio è la funzione eseguita dal server. Se una stampante è un server, il servizio che fornisce è la stampa.
Gli handler degli eventi vengono utilizzati nel TSD Script e Developer's Toolkit per supportare un ambiente basato
sugli eventi. In un ambiente gestito dagli eventi, un evento (come
una sequenza tasti, un clic del mouse o un messaggio di rete) esegue
un trigger della risposta tramite l'applicazione (come l'apertura di una
nuova casella di dialogo o la selezione di una voce in un campo). Per
elaborare gli eventi, ogni applicazione utilizza gli handler degli
eventi creati espressamente per tali eventi.
Non è necessario che le applicazioni che utilizzano gli handler degli
eventi richiedano o "effettuino il polling" per gli
eventi di rete. Solitamente, gli handler degli eventi
"sleep" (sono inattivi) fino a che non si verifica un
evento, poi elaborano una richiesta per il servizio.
Un server singolo può avere più handler degli eventi. Ogni handler
degli eventi è progettato per fornire un servizio specifico o una
serie di servizi correlati, come spiegato successivamente in questo
capitolo.
Gli handler degli eventi sono definiti nella sezione delle
routine di un programma TSD Script. Gli handler degli eventi di rete
devono essere dichiarati come tipo NETCONNECTION.
Questo tipo di handler degli eventi è diverso dal tipo di default, WINDOW. Poiché
il tipo determina la $Handle utilizzata, solo gli
handler degli eventi di tipo NETCONNECTION possono
essere utilizzati con le istruzioni NETx.
NETCONNECTION EVENT TalkConnectEvent( REF whdl: WINDOW ) IS
Quando viene definito un handler degli eventi, è necessario
registrare anche il servizio a esso relativo, come descritto nelle
sezioni che seguono. La registrazione di un handler degli eventi associa
l'handler all'origine degli eventi.
E' possibile utilizzare due istruzioni diverse per registrare un
handler degli eventi:
Gli handler degli eventi registrati con NetRegister sono definiti handler degli eventi NetRegister. Gli handler degli eventi registrati con NetListen sono definiti handler degli eventi NetListen.
Questo capitolo focalizza l'attenzione sull'uso di NetRegister, utilizzato di frequente per gli handler degli eventi "standard". Per la personalizzazione di handler degli eventi, consultare la sezione "Istruzioni avanzate" in questo capitolo.
E' necessario registrare un handler degli eventi con il server affinché questo riceva ed elabori le richieste del servizio. Per registrare un handler degli eventi con l'istruzione NetRegister, utilizzare la seguente sintassi:
NetRegister (TalkConnectEvent, 'Talk');
Quando si registra un handler degli eventi, specificare il nome del servizio da esso fornito. Un servizio è costituito da una categoria di azioni effettuate dall'handler degli eventi.
Nell'esempio che segue, il nome del servizio definito per l'handler degli eventi di rete TalkConnectEvent è Talk.
NETCONNECTION EVENT TalkConnectEvent( REF whdl: WINDOW ) IS ACTIONS . .. END; NetRegister (TalkConnectEvent, 'Talk');
Oltre ai servizi precedentemente trattati, viene supportata un'estensione del numero di porta che specifica una porta IP. Il numero di porta controlla:
La porta di default è 5001 e il servizio di default è asenet/tcp. Se il servizio è nel file di servizi, asenet/tcp viene utilizzato al posto del numero di default.
E' possibile specificare un numero di porta nella richiesta comandi con il seguente comando:
/p=nnn
Un numero di porta emesso da una richiesta comandi sostituisce sia la porta di default che il servizio di default.
Nota: I numeri di porta devono essere gli stessi per il client e per il server.
E' possibile creare un handler degli eventi con un servizio
definito come stringa di lunghezza zero ('') o come $Unknown. Questo
tipo di servizio viene definito come servizio carattere jolly.
Quando sul server viene definito un servizio carattere jolly, esso
serve tutte le richieste specificate dal client per cui il server non
riesce a trovare un nome del servizio corrispondente.
E' inoltre possibile definire un servizio carattere jolly sul
client. In questo caso, il server deve disporre di un servizio che abbia un nome
'' oppure $Unknown.
Nota: E' possibile definire un servizio carattere jolly
solo quando si registra un handler degli eventi
con l'istruzione NetRegister. (NetListen
utilizza sempre un servizio carattere jolly.)
Quando si registra un handler degli eventi, viene definito un modulo per il servizio sul server. Questo modulo include informazioni derivanti dalla definizione dell'handler degli eventi nella sezione delle routine del codice e le informazioni specificate al momento della registrazione dell'handler degli eventi.
Il modulo viene mantenuto in memoria fino a che non viene
richiesta una connessione. Quindi, le informazioni del modulo
vengono utilizzate per stabilire il servizio per la connessione.
E' possibile apportare due tipi di modifiche di base a un modulo:
Quando è necessario apportare modifiche a un modulo, è possibile registrare nuovamente l'handler degli eventi o registrare il servizio a esso relativo. Se si registra nuovamente un handler degli eventi, i nuovi valori del parametro vengono implementati immediatamente. Tutte le nuove connessioni aperte per il modulo utilizzeranno i nuovi valori. Le modifiche apportate al modulo non interessano le connessioni esistenti.
Avvertenza: E' necessario specificare il nome del servizio esattamente come specificato nel modulo di origine. Altrimenti, l'istruzione NetRegister crea un nuovo modulo per l'handler degli eventi e il modulo esistente non verrà modificato.
Una volta creato un modulo, esso diventa immediatamente e continuamente ricettivo alle richieste del servizio. Tuttavia, è possibile arrestare, in un qualsiasi momento, un modulo che risponde alle richieste del servizio. Per effettuare ciò, registrare nuovamente il servizio con l'handler degli eventi speciale $NullHandler:
NetRegister ($Nullhandler, 'servizio');
In questa sintassi, "servizio" è il nome del servizio associato all'handler degli eventi che si desidera arrestare.
Dopo aver registrato nuovamente il servizio con $NullHandler, le future richieste del servizio effettuate dal modulo vengono negate, ma non vengono influenzate le connessioni esistenti che utilizzano il modulo.
Per riavviare il server, è necessario avviare nuovamente l'handler degli eventi e il servizio a esso relativo.
Un handler degli eventi può effettuare connessioni con più client. Potrebbe risultare difficile, considerando solo l'handle della connessione, stabilire quale servizio è in esecuzione.
Allo stesso modo, potrebbe essere difficile stabilire quale server sta effettuando il servizio o quale client viene servito. Ciò è particolarmente vero per l'handler degli eventi NetListen, che risponde a ogni richiesta di servizio ricevuta e ne condivide i dati d'istanza.
TSD Script fornisce due istruzioni da utilizzare per ottenere informazioni sull'host (server) e su un servizio da una handle di connessione:
Poiché TSD Script supporta un'architettura client/server e un'architettura peer-to-peer, l'istruzione NetGetHostName ha lo scopo di ottenere informazioni sulla macchina remota, senza considerare se sta svolgendo o meno il ruolo del server.
Se viene chiamata l'istruzione NetGetHostName sul client, si ottengono le informazioni relative al server. Se viene chiamata l'istruzione NetGetHostName sul server, si ottiene il nome del client.
E' possibile che esistano molti handler degli eventi NETCONNECTION su ogni server. Talvolta, potrebbe essere necessario trasferire i messaggi tra questi. Poiché non è produttivo inviare questi messaggi all'interno di una rete, Developer's Toolkit fornisce l'istruzione NetLoopBack. NetLoopBack consente di inviare un messaggio a un handler degli eventi di rete dalla macchina locale.
Le applicazioni di rete TSD Script utilizzano un protocollo basato
sulla connessione. L'interazione tra le macchine su una rete si
verifica tramite una connessione. Perché un server fornisca a un
client un servizio richiesto, è necessario aprire una connessione.
In una connessione esistono tre elementi:
La combinazione di questi tre elementi rende unica la connessione. Il
processo di apertura e di chiusura di una connessione include ognuno
di questi tre elementi.
E' possibile aprire più connessioni tra un client e un server. Tuttavia,
un client può avere solo una connessione aperta per un servizio
specifico su un server/porta.
Nota: Se è già aperta una connessione tra un client e un handler
degli eventi specifico su un server, la richiesta di un
servizio specifico restituisce l'handle della connessione esistente.
Dopo aver registrato un handler degli eventi e il servizio a esso associato, il server è pronto a ricevere le richieste per il servizio specificato.
Questa sezione descrive il processo apertura di una connessione ed elenca le fasi della procedura utilizzata per aprire una connessione.
Le procedure di apertura di una connessione e la spiegazione di ogni passo vengono riportate di seguito.
Quando un client richiede un servizio, esso deve specificarne il nome esatto. (Il nome del servizio viene definito quando l'handler degli eventi viene registrato sul server). Non esiste un elenco che comprende tutti i servizi disponibili forniti da un server e i nomi dei servizi non sono sensibili al maiuscolo-minuscolo.
E' possibile specificare una porta come parte della stringa del servizio. Se nessuna porta viene specificata, viene utilizzata quella di default.
Un client può richiedere un servizio carattere jolly specificando una stringa di lunghezza zero oppure $Unknown. In questo caso, per soddisfare la richiesta, il server deve disporre di un servizio con nome NetListen oppure $Unknown.
Nota: Se il client richiede un servizio non definito sul server e se non vi è un servizio carattere jolly o NetListen definito, il server mette in corrispondenza la richiesta del client con il servizio carattere jolly.
Se il client non può comunicare con il server, viene restituito al client stesso un codice di errore HOST_UNREACHABLE (-13).
Se un server TSD Script non è in esecuzione, al client viene restituito un codice di errore -13 HOST_UNREACHABLE.
Se la connessione è già stata stabilita, viene restituito TRUE al client. Viene restituita anche l'handle per la connessione.
Se viene trovato il nome del servizio corrispondente, il server restituisce una handle al client. L'handle indica una copia del modulo che fornisce il servizio. Quando il client riceve l'handle, può continuare con l'elaborazione.
Se il server trova un servizio carattere jolly, restituisce l'handle al client. L'handle indica una copia del modulo che fornisce il servizio carattere jolly. Quando il client riceve l'handle, può continuare con l'elaborazione.
Se viene trovato un handler degli eventi NetListen, al client viene restituita una handle che descrive la connessione alla macchina client. Se trovata, l'handle punta direttamente sull'handler degli eventi NetListen. Quando il client riceve l'handle, continua con l'elaborazione dei dati degli eventi.
Se viene trovato un handler degli eventi NetListen, passare alla fase 10. Se non viene trovato un handler degli eventi NetListen, procedere con la fase 8.
Quando $MsgNetConnect viene elaborato sul server, la connessione viene aperta e il servizio può essere utilizzato.
Solitamente, il processo di chiusura di una connessione viene iniziato dal client. Tuttavia, anche il server può iniziare la chiusura. In entrambi i casi, per chiudere la connessione viene utilizzata l'istruzione NetClose.
Nota: Se il client o il server va in crash, la connessione tra essi si perde. Per ristabilire la comunicazione tra le macchine, è necessario riaprire la connessione.
Quando un client chiude una connessione, si verifica quanto segue:
Nota: Se l'handler degli eventi è NetListen, non esistono dati d'istanza specificamente definiti per la connessione. Il processo di chiusura è completo quando l'handle è ritenuta chiusa. Non viene inviato nessun messaggio $MsgNetDestroy.
Se il programma del client o del server termina o se si verifica un'interruzione nella rete, ripetere le fasi 2 e 3.
Se il server avvia la chiusura della connessione, non vi sono comunicazioni che dal server ritornano al client.
La volta successiva in cui il client tenta di comunicare con il
server, esso rileva la chiusura e crea un messaggio di errore come
"handle non valida."
In un ambiente peer-to-peer NetClose chiude le
connessioni del client e del server.
I dati d'istanza sono dati TSD Script definiti dall'utente relativi a una connessione. I dati d'istanza vengono creati al momento della creazione della connessione e distrutti quando questa viene chiusa.
L'handler degli eventi riceve un riferimento ai dati d'istanza con tutti i messaggi per la connessione. I dati d'istanza memorizzano le informazioni specifiche per la connessione.
Quando si registra un handler degli eventi con NetRegister, è possibile specificare un valore iniziale per i dati d'istanza di quell'handler degli eventi. Tutte le connessioni aperte per il modulo ricevono una copia dei dati d'istanza inizializzati per il valore specificato oppure per $Unknown se non viene fornito nessun valore iniziale.
Durante la specifica dei dati d'istanza, ricordare quanto segue.
Ad esempio:
connectionData is Record callCount = INTEGER; . . . END;
NETCONNECTION EVENT MyEvent (REF data: ConnectionData); ACTIONS When $Event IS $MsgCreate Then data.callCount=1; . . . END; END; StmtData : ConnectionData; NetRegister( MyEvent {StartDate}, 'Service');
Quando si apre una connessione, i dati d'istanza definiti per l'handler degli eventi vengono forniti come esempio nella copia del modulo per la connessione e viene loro assegnato il valore iniziale. Questo processo viene definito inizializzazione.
Se si imposta il valore dei dati d'istanza su $Unknown nel modulo, ciò indica che l'inizializzazione non avviene.
Inoltre, l'inizializzazione non si verifica a meno che non si imposti un valore per il valore iniziale dei dati d'istanza. Se il valore non viene impostato, si presume che il valore iniziale sia $Unknown.
Potrebbero essere aperte più connessioni per un handler degli eventi NetRegister. Ognuna di queste connessioni dispone di una copia dei dati d'istanza.
Un client può inviare, in un qualsiasi momento, una richiesta a un server, senza considerare se il server è attualmente in fase di gestione di una richiesta precedente o meno. A seconda della velocità con cui il client richiede una risposta dal server e se il client richiede che vengano restituiti i dati dal server, può inviare la richiesta con l'istruzione di bloccaggio o con quella di non bloccaggio:
Quando un server riceve le richieste, le aggiunge alla coda. Il server elabora le richieste nell'ordine in cui sono state ricevute. (In alcuni casi, il server può inserire i messaggi di bloccaggio nella coda nella parte opposta dei messaggi di non bloccaggio). A seconda delle condizioni della rete, il server può soddisfare una richiesta con tempi diversi.
Se l'istruzione inviata al server è di bloccaggio, al client non
viene restituita nessuna informazione fino a che non viene completato
l'intero processo sul server.
SendMessage è l'unica istruzione di bloccaggio in TSD Script.
Per evitare lo stallo tra un client e il server, può essere attivo
solo un SendMessage alla volta sulla connessione.
Se l'istruzione inviata al server è di non bloccaggio, il server restituisce una risposta al client che "ha ricevuto la richiesta" quando l'istruzione è stata aggiunta alla coda. Il client può continuare, dunque, l'elaborazione.
Esistono varie istruzioni di non bloccaggio:
Per comunicare con il server è possibile scegliere tra istruzioni di bloccaggio e di non bloccaggio. La selezione di entrambi i tipi potrebbe risultare rischiosa per i seguenti motivi:
In TSD Script e Developer's Toolkit, le handle vengono utilizzate in modo estensivo per mantenere traccia dell'attività di rete e della finestra.
Le handle sono necessarie per le connessioni con le istruzioni SendMessage o PostMessage. Queste sono, rispettivamente, istruzioni di bloccaggio e non bloccaggio. Questa caratteristica determina il comportamento del client e del server.
Il server apre una handle quando individua il modulo dell'handler degli eventi con il servizio che corrisponde al servizio richiesto dal client. L'handle è contenuta nel parametro $Handle e trasferita al gruppo eventi che serve la connessione.
Il server considera chiusa una handle quando esso chiude la connessione. Se si tenta di accedere a una connessione chiusa, si riceve un messaggio di errore (Invalid_Handle).
Le istruzioni NETx di TSD Script possono essere utilizzate sia nelle architetture client/server che in quelle peer-to-peer. Per gestire queste architetture, esistono due formati per l'istruzione NetConnect.
Nell'architettura client/server il client deve specificare un nome e servizio host in modo che il server possa rispondere alla richiesta del client e restituire i servizio in modo da in modo che il server possa rispondere alla richiesta del client e restituire il servizio richiesto.
FUNCTION NetConnect(REF hndlHost: NETCONNECTION, .VAL hostName: STRING, . VAL service: STRING .): INTEGER;
Per rispondere al client nell'architettura peer-to-peer, il server deve aprire una connessione di ritorno. Il formato peer-to-peer rappresenta una scorciatoia per la creazione di una connessione di ritorno. Questo formato è facoltativo; è possibile ottenere lo stesso risultato utilizzando il formato client/server.
FUNCTION NetConnect( VAL hndlHost: NETCONNECTION ): INTEGER;
E' necessaria una sola handle per una connessione peer-to-peer. L'handle conterrà tutti i dati della connessione.
Per una descrizione dettagliata di NetGetHostName o NetGetService, consultare il capitolo successivo.
Utilizzare la costante $Handle per inviare una risposta a un server remoto. E' possibile inizializzare una connessione di ritorno con la riga seguente:
NetConnect( $Handle );
Finora, in questo capitolo si è parlato di metodi "standard" per la creazione e la registrazione di un handler degli eventi utilizzando l'istruzione NetRegister. Per le applicazioni che richiedono un maggior controllo sulle connessioni, TSD Script fornisce una serie alternativa di istruzioni da utilizzare insieme per registrare un handler degli eventi. Queste istruzioni sono:
Gli handler degli eventi NetAccept sono molto simili agli handler degli eventi NetRegister.
Nota: Non è necessario utilizzare entrambe le istruzioni NetListen e NetAccept per ottenere un'applicazione di rete completamente funzionale.
Questa tabella riassume le differenze tra gli handler degli eventi NetRegister e NetListen.
Poiché NetListen non crea nuovi dati d'istanza per ogni connessione, il processo di apertura di una connessione tramite NetListen è leggermente più veloce.
NetListen è utile per facilitare i servizi che non richiedono la gestione di un contesto tra un messaggio e l'altro.
Termine di paragone | NetRegister | NetListen |
Numero di handler degli eventi | E' possibile che più handler degli eventi NetRegister siano in esecuzione contemporaneamente su un server. | E' possibile che solo un handler degli eventi NetListen sia definito per un server. |
Servizio registrato | Un handler degli eventi NetRegister viene registrato con un servizio specifico. Il client deve richiedere esattamente quel nome servizio per ottenere una corrispondenza del servizio con il modulo appropriato. | Un handler degli eventi NetListen non dispone di un servizio specifico a esso associato. Una corrispondenza del servizio viene eseguita solo con l'handler degli eventi NetListen solo se non esistono moduli corrispondenti sul server. |
Modulo | Quando si registra un handler degli eventi NetRegister, viene creato un modulo per esso. Il modulo contiene tutte le informazioni specifiche sulla connessione. | Nessun modulo viene creato quando si registra un handler degli eventi NetListen. Le informazioni specifiche sulla connessione devono essere gestite dall'applicazione. |
Dati d'istanza | Ogni connessione dispone di una copia dei dati d'istanza. | Esiste una serie di dati d'istanza definita per l'handler degli eventi. Ogni connessione aperta per l'handler degli eventi condivide quei dati d'istanza. |
Porte | Il servizio può utilizzare porte alternative. | Il servizio può utilizzare solo la porta di default. |
E' possibile che gli handler degli eventi NetListen e NetRegister siano in esecuzione contemporaneamente su un server. Poiché un client non sa come viene soddisfatta una richiesta, non può richiedere specificatamente l'handler degli eventi da utilizzare.
Gli handler degli eventi NetListen vengono utilizzati per servizi che non richiedono che le informazioni sul contesto siano conservate per una connessione. Gli handler degli eventi NetListen richiedono meno risorse del server e creano connessioni in maniera leggermente più veloce rispetto a quelle degli handler degli eventi NetRegister.
La richiesta del client viene messa in corrispondenza con un handler degli
eventi NetListen solo se non è possibile creare
nessun'altro tipo di corrispondenza (incluso un modulo carattere
jolly). Il client invia il nome del servizio all'handler degli eventi NetListen sul server. L'handler
degli eventi NetListen deve interrogare l'handle
per il servizio con NetGetService.
Il client, tuttavia, non garantisce che il servizio sia assicurato
dal server.
E' possibile che più connessioni NetListen siano aperte contemporaneamente, poiché ogni connessione condivide gli stessi dati d'istanza con altre connessioni aperte. Perciò, quando si chiude una connessione NetListen, i dati d'istanza non vengono distrutti.
Una volta chiusa una connessione NetListen, è necessario ripulire le risorse per la connessione chiusa.
L'handle per ogni connessione NetListen dispone delle informazioni sul tipo di servizio specifico richiesto dal client.
L'handler degli eventi NetListen non associa i dati d'istanza a ogni connessione. Invece, è necessario tenere traccia di ogni connessione e delle relative attività. La capacità di tracciare connessioni individuali è un beneficio ulteriore dell'utilizzo dell'istruzione NetListen per registrare gli handler degli eventi.
Ogni connessione aperta per NetListen condivide la copia dei dati d'istanza definita per l'handler degli eventi NetListen. Se si desidera associare una serie specifica di dati d'istanza a una delle connessioni NetListen aperte, è possibile chiamare l'istruzione NetAccept per quella connessione.
Nota: NetAccept può essere chiamato solo per una connessione NetListen. E' possibile accedere alla connessione utilizzando l'handle a essa relativa. Inoltre, NetAccept può associare un nuovo handler degli eventi alla connessione.
I dati d'istanza associati alla connessione non vengono utilizzati con nessun'altra connessione attualmente aperta o da aprire in futuro per l'handler degli eventi NetListen. Una volta chiamato NetAccept, la connessione viene modificata.
Tutte le richieste per la stessa coppia host/service sono indirizzate direttamente al nuovo handler degli eventi.
Nota: Potrebbe rivelarsi più semplice utilizzare NetRegister, perché la combinazione di NetListen e di NetAccept conduce allo stesso risultato.
Questo esempio illustra come impostare un programma talk semplice tra due computer in rete. Questo programma spiega l'interazione tra due macchine in un ambiente peer-to-peer.
KNOWLEDGEBASE NetTalk;
CONSTANTS menuList IS { '~File', 'e~Xit', '', '~Host', '~Open', '', '~Help', '~About', '' }: LIST OF STRING; MsgUserChar IS $MsgUser; MsgRemoteChar IS $MsgUser + 1; MsgTalkClose IS $MsgUser + 2;
ROUTINES
EVENT TalkMainEvent; FUNCTION CreateTalkWindow( VAL host: NETCONNECTION ) : WINDOW; PROCEDURE NetTalkMain;
PRIVATE TYPES TALK_RECORD IS RECORD xLen: INTEGER; -- Width of window in characters yLen: INTEGER; -- Height of window in characters whdlMe: WINDOW; -- Window where local input is displayed whdlYou: WINDOW; -- Window where remote input is displayed host: NETCONNECTION; -- host handle END;
PANNEL_DATA IS RECORD whdlParent: WINDOW; curX: INTEGER; -- X location of cursor on the window curY: INTEGER; -- Y location of cursor on the window lines: LIST OF STRING; -- List of all lines being edited END;
ROUTINES
NETCONNECTION EVENT TalkConnectEvent( REF whdl: WINDOW ) IS VARIABLES result : INTEGER;
ACTIONS WHEN $Event IS $MsgNetConnect THEN -- Create a talk window. -- Create a connection to service this talk session result := NetConnect( $Handle ); IF result < 1 THEN WinMessageBox(whdl,'Error',$MBOk + $MBIconError, 'Connection failed ERROR ' & result ); Exit(0); END; whdl := CreateTalkWindow( $handle ); IF whdl = $UNKNOWN THEN WinMessageBox(whdl,'Error',$MBOk + $MBIconError, 'Window creation failed' ); NetClose( $Handle ); Exit(0); END; ELSWHEN MsgRemoteChar THEN -- Pass the character from the remote machine to the talk window SendMessage( whdl, MsgRemoteChar, $KeyCode ); ELSWHEN MsgTalkClose THEN NetClose( $Handle ); ELSWHEN $MsgNetClose THEN -- When the windows close on the remote machine clean up here SendMessage( whdl, $MsgClose ); NetClose( $Handle ); END; END;
EVENT TalkMainEvent IS VARIABLES host : NETCONNECTION; hostName : STRING; result : INTEGER;
ACTIONS WHEN $Event IS $MsgCreate THEN WinSetMenuBar( $Handle, menuList ); ELSWHEN $MsgMenu THEN WHEN $MenuSelection IS 101 THEN SendMessage( $Handle, $MsgClose ); ELSWHEN 201 THEN WinEditField($Desktop, hostName, 0, 0, 40, 'Enter host name', BitOr($WinTitle, $WinBorder, $WinAutoPos ) ); -- Create a talk connextion to hostname result := NetConnect( host, hostName, 'Talk' ); IF result <> 1 THEN WinMessageBox($Handle, 'Error', $MBOk + $MBIconError, 'Connection failed ERROR ' & result ); END; END; END; END; EVENT TalkPannelEvent( REF pannelData: PANNEL_DATA ) IS ACTIONS WHEN $Event IS $MsgCreate THEN pannelData.curX := 1; pannelData.curY := 1; ListInsert( pannelData.lines, '' ); ELSWHEN $MsgPaint THEN -- Clear window, and re display contents WinSetFont($Handle, 'System Monospaced', 10, 0 ); WinClear($Handle ); WinWriteLn($Handle, pannelData.lines ); ELSWHEN $MsgChar THEN -- The parent window processes all characters immessi SendMessage(pannelData.whdlParent, $MsgChar, $KeyCode ); ELSWHEN MsgUserChar THEN WHEN $KeyCode IS $KeyReturn THEN -- Enter key is a new line pannelData.curX := 1; pannelData.curY := pannelData.curY + 1; ListInsert(pannelData.lines, '' ); ELSE -- Add character to current line, and display it WinSetFont($Handle, 'System Monospaced', 10, 0 ); WinGotoXY($Handle, pannelData.curX, pannelData.curY ); WinWrite($Handle, Char( $KeyCode ) ); pannelData.curX := pannelData.curX + 1; pannelData.lines[ $CURRENT ] := StrInsert(pannelData.lines [ $CURRENT ], Char( $KeyCode ), 1000 ); END; END; END;
EVENT TalkEvent( REF talkData: TALK_RECORD ) IS VARIABLES pannel : PANNEL_DATA; yLen : INTEGER;
ACTIONS WHEN $Event IS $MsgCreate THEN -- Create 2 display panels for local, and remote characters and pass in parent pannel.whdlParent := $Handle; padre yLen := talkData.yLen / 2; WinCreate($Handle, talkData.whdlMe, TalkPannelEvent{ pannel }, 0, 0, talkData.xLen, yLen, '', $WinField ); yLen := talkData.yLen - yLen; WinCreate($Handle, talkData.whdlYou, TalkPannelEvent{ pannel }, 0, yLen + 1, talkData.xLen, yLen,'', $WinField ); ELSWHEN $MsgDestroy THEN PostMessage( talkData.host, MsgTalkClose ); ELSWHEN $MsgSize THEN -- Position and size panels to fit window when it is resized talkData.xLen := $EventParm( 1, INTEGER ); talkData.yLen := $EventParm( 2, INTEGER ); yLen := talkData.yLen / 2; SendMessage(talkData.whdlMe,$MsgSetSize talkData.xLen, yLen); yLen := talkData.yLen - yLen; SendMessage(talkData.whdlYou,$MsgSetSize, talkData.xLen,yLen ); SendMessage(talkData.whdlYou,$MsgMove,1, yLen + 1 ); ELSWHEN $MsgChar THEN -- Send local characters to top pannel for display SendMessage(talkData.whdlMe, MsgUserChar, $KeyCode ); -- also send character to remote host to display PostMessage(talkData.host, MsgRemoteChar, $KeyCode ); ELSWHEN MsgRemoteChar THEN -- Send remote character to bottom pannel for display SendMessage(talkData.whdlYou, MsgUserChar, $KeyCode ); ELSWHEN $MsgPaint THEN WinClear( $Handle ); END; END;
FUNCTION CreateTalkWindow( VAL host : NETCONNECTION ) : WINDOW IS VARIABLES whdlNetTalk: WINDOW; talkData: TALK_RECORD; result : INTEGER;
ACTIONS talkData.host := host; risultato := WinCreate($Desktop, whdlNetTalk, TalkEvent{talkData}, 0, 0, 0, 0, NetGetHostName(host), BitOr($WinBorder, WinTitle, $WinResize, $WinSysMenu, $WinAutoSize, $WinAutoPos, $WinTaskList)); IF result < 1 THEN WinMessageBox($Desktop, 'Error', $MBOk + $MBIconError, 'Cannot create talk main window. Error: ' &result ); END; EXIT( whdlNetTalk ); END;
PROCEDURE NetTalkMain IS VARIABLES whdlNetTalk: WINDOW; result : INTEGER;
ACTIONS risultato := WinCreate($Desktop, whdlNetTalk, TalkMainEvent, 0, 0, 40, 0, 'Network talk program', BitOr($WinBorder, $WinTitle, $WinResize, $WinSysMenu, $WinMenu, $WinTaskList)); IF result < 1 THEN WinMessageBox($Desktop, 'Error', $MBOk + $MBIconError, 'Cannot create talk main window. Error: ' &result ); END; NetRegister (TalkConnectEvent, 'Talk'); WinWait( whdlNetTalk ); END;
Manuale per la programmazione Tivoli Service Desk 6.0 Developer's Toolkit Script