Sincronizza Indice |
Scarica il progetto |
Testo dell'articolo |
Stampa l'articolo |
L'articolo prende spunto da quello dedicato alla creazione di un singolo controllo Winsock in un modulo di classe ed implementa una soluzione basata sull'uso di due classi collegate: la prima servirà per allocare un singolo controllo e la seconda raggruppa i vari controlli e ne gestisce gli eventi.
All'interno della classe il gruppo di controlli può essere gestito mediante un array oppure mediante una Collection. L'uso della prima soluzione piuttosto che della seconda è determinato da una costante di compilazione condizionale. Vedi le Informazioni aggiuntive sulla compilazione condizionale. Sebbene le due classi siano inscindibili ed interdipendenti l'una dall'altra cominceremo a vedere il codice della prima classe: clsFBIOnClassSocketSingle:
Alle righe 3-5 sono dichiarate le tre variabili membro utilizzate dalla classe: m_Socket è un controllo Windockcon eventi creato mediante la terza soluzione del tutorial precedente. Tutti i suoi eventi saranno passati al gruppo clsFBIOnClassSocketGroup, che lo contiene, identificato dalla variabile m_Parent. L'ultima variabile membro m_InGroupIndex conterrà l'indice di questa istanza all'interno del gruppo identificato da m_Parent. L'enumerazione WinsockEvents (righe 7-15) verrà utilizzata per comunicare l'esecuzione di un evento dal controllo Winsock alla classe clsFBIOnClassSocketGroup.
All'istanza del controllo sarà allocato il nuovo controllo Winsock (riga 18) ed inizializzato il valore m_InGroupIndex a -1. In maniera analoga, alla deallocazione dell'istanza sarà inizialmente chiusa l'eventuale connessione lasciata aperta (riga 25) e verranno deallocati i due oggetti m_Socket ed m_Parent.
Quelli sopra mostrati sono tutti gli eventi ricevuti dal controllo m_Socket e per ognuno di essi sarà richiamato il metodo NewEvent della classe clsFBIOnClassSocketGroup fornendogli come primo argomento l'indice dell'elemento all'interno del gruppo, indicato da m_InGroupIndex, come secondo argomento un valore dell'enumerazione WinsockEvents e come altri argomenti tutti i dati ricevuti dall'evento del controllo. Questo farà sì che l'istanza m_Parent riceverà l'evento generato dal controllo e l'indice del controllo all'interno del gruppo, in modo da comunicarlo all'esterno della classe e permettere al programma la gestione degli eventi dei singoli controlli all'interno del gruppo.
La proprietà Socket restituisce il controllo Winsock mantenuto all'interno della classe, per permettere l'impostazione e l'uso dall'esterno.
L'ultima funzione della classe è AddToGroup e consente di aggiungere l'istanza corrente ad un gruppo clsFBIOnClassSocketGroup, che si occuperà di gestire gli eventi in maniera associata all'indice dell'istanza all'interno del gruppo. La seconda classe clsFBIOnClassSocketGroup si occuperà di collegare più istanze della classe clsFBIOnClassSocketSingle in un unico gruppo. La sua reale funzione è quella di consentire la creazione di un nuovo controllo Winsock, restituire quelli già esistenti e gestire gli eventi provenienti dai singoli controlli Winsock. Vediamone subito il codice:
L'istruzione Option Base 1 alla riga 2 determina che il limite inferiore di tutte le matrici sia 1, anziché 0; è stato richiesto appositamente per mantenere la compatibilità tra la Collection (sempre a base 1) e l'array di istanze clsFBIOnClassSocketSingle (solitamente a base 0).
La costante di compilazione condizionale USEARRAY determina infatti se il codice farà uso della matrice oppure dell'oggetto Collection. La dichiarazione della base dati SocketsInterni è effettuata alle righe 6-10. Naturalmente una delle dichiarazioni esclude automaticamente l'altra. La variabile intSocketsCount alla riga 12 tiene conto del numero di controlli Winsock contenuti.
L'enumerazione WinsockEvents, vista anche nella classe precedente, verrà utilizzata dalla classe per identificare con facilità quale evento è stato ricevuto. Tali eventi a loro volta saranno rilasciati sull'utilizzatore dell'istanza; gli eventi dichiarati alle righe 24-30 sono i medesimi di un normlae controllo Winsock ma vi aggiungono un primo argomento di nome Index, che identifica il singolo controllo nel gruppo, come se si trattasse di una matrice di controlli posta sopra un form.
All'istanza della classe il numero di elementi contenuti nel gruppo è 0 (riga 33). Se è stato scelto di usare un oggetto Collection piuttosto che un array, esso sarà istanziato alla riga 35. Alla deallocazione dell'istanza sarà necessario fare un po' di pulizia: saranno deallocati uno per uno tutti gli oggetti del gruppo (righe 42-44 e 47-49); inoltre nel caso di un gruppo Collection sarà deallocata anche l'istanza SocketsInterni (riga 45); nel caso fosse un array esso sarà semplicemente azzerato (riga 50).
Le tre proprietà sopra dichiarate restituiscono rispettivamente il numero di controlli contenuti nel gruppo (righe 54-56), il tipo di gruppo utilizzato (righe 58-64) ed il controllo Winsock identificato dal'indice Index all'interno del gruppo.
Se la classe sta facendo uso di un oggetto Collection sarà aggiunta
una nuova proprietà (nascosta) di nome NewEnum. Essa consentirà
l'iterazione con tutti gli elementi del gruppo in un ciclo For..Each. Importante!
Il metodo più complesso della classe è Add, che aggiunge un'istanza clsFBIOnClassSocketSingle al gruppo e restituisce in uscita un riferimento al controllo Winsock generato. La variabile newSocketSingle si è dimostrata obbligatoria per superare uno sciocco limite degli oggetti Collection. Infatti sebbene ogni elemento della Collection sia un'istanza della classe clsFBIOnClassSocketSingle, Visual Basic non consente l'uso implicito di un elemento della Collection per operazioni su oggetti, come ad esempio SocketsInterni(i).AddToGroup. Pertanto alla riga 78 è allocata una nuova istanza della prima classe ed alle righe 79-84 essa è aggiunta al gruppo SocketsInterni, nella forma consentita da una fra le due basi di dati. Alla riga 86 la nuova istanza è aggiunta al gruppo corrente mediante AddToGroup, per consentirle la comunicazione dei suoi eventi al gruppo di appartenenza. In uscita dalla funzione saranno in ordine restituiti il nuovo controllo Winsock creato e deallocata la variabile temporanea newSocketSingle.
L'ultima funzione della classe è NewEvent, dichiarata come Friend perché dovrebbe essere utilizzata esclusivamente dalle classi clsFBIOnClassSocketSingle per la comunicazione degli eventi generati. La funzione utilizza un numero indefinito di argomenti: i primi due argomenti identificano l'indice del controllo all'interno del gruppo e l'evento generato, come da enumerazione WinsockConstants. Il terzo argomento è un Paramarray, cioè in grado di ricevere un numero indefinito di altri argomenti, che saranno quindi forniti ai singoli eventi richiamati. Il funzionamento di questo metodo è in realtà molto semplice: in base al valore dell'evento generato sarà richiamato l'evento di questa classe, che verrà fornito all'utilizzatore della stessa. Si tratta quindi di un semplice passaggio di dati dalla prima classe alla seconda e da questa verso il programma utilizzatore.
Per dimostrare il funzionamento delle due classi sarà sviulppato una microscopica chat punto-punto composta da un solo form e 5 caselle di testo.
All'interno del form sarà allocata una nuova istanza clsFBIOnClassSocketGroup e dichiarata con WithEvents in modo da poterne ricevere gli eventi di ritorno:
Così al caricamento del form l'istanza Sockets è allocata e con essa (alle righe 9-12) sono creati due controlli Winsock nel gruppo dei quali uno è posto in ascolto sulla porta TCP 1000 (riga 10) e l'altro si connette al primo (riga 12). Inoltre, se è stato deciso di utilizzare la Collection invece dell'array di controlli, sarà eseguito un ciclo iterativo con For..Each (righe 14-16) che mostrerà nella finestra immediata l'indirizzo delle porte locali dei due controlli. Naturalmente la sua funzionalità è puramente simbolica per dimostrare il funzionamento della proprietà NewEnum della classe, in un ciclo For..Each.
L'evento ConnectionRequest di uno dei due controlli si rispecchia automaticamente (mapping) sul medesimo evento dell'istanza Sockets. Tra gli argomenti il primo identifica il controllo Winsock nel gruppo che ha generato l'evento. Nel caso specifico al tentativo di collegamento si risponderà con la chiusura dalla fase d'ascolto e con l'accoglimento della connessione, in questo caso, del primo controllo.
Tralasciamo il resto del codice, più o meno inutile all'uso della classe e vediamo l'uso di un altro evento dell'istanza Sockets: DataArrival. Alla riga 29 sono letti i dati diretti al controllo interessato ed alla riga successiva è verificata la destinazione dei dati (argomento Index). Se i dati sono diretti al primo controllo (riga 30) dovranno essere quindi
essere inviati alla casella dei messaggi del primo controllo txtCli1Log;
viceversa i dati saranno inviati alla casella txtCli2Log. |
Non è stato possibile affrontare l'argomento della microchat completamente perché avrebbe richiesto troppo spazio. La sua funzionalità tuttavia è davvero molto semplice e si è preferito dedicare maggiore spazio alle due classi clsFBIOnClassSocketSingle e clsFBIOnClassSocketGroup che formano il gruppo di controlli Winsock. Il loro funzionamento è davvero molto semplice e per molti versi
simile al comportamento di una matrice di controlli Winsock posti sopra
la superficie di un form. Fibia
FBI
|
Torna all'indice Client/Server |