2012-02-27 1 views
21

Ho una grande applicazione Delphi che ha il codice 'server' principale che contiene i miei dati. All'interno della stessa app, 'client' l'utente è in grado di aprire e chiudere più moduli 'client' non modali per ispezionare questi dati. Le modifiche ai dati si suddividono in due tipi: principali (ad esempio modifiche strutturali come i dati sono stati aggiunti o eliminati) e minori, come una modifica a un valore di dati. I moduli client aperti esistenti devono essere aggiornati per mostrare i dati modificati entro un tempo breve. Questo non è un database, il mio "server" utilizza le mie strutture di dati, quindi le mie soluzioni potrebbero aver perso alcune tecniche standard disponibili all'interno di una struttura di database formale. Detto questo, ho ripetuto le mie soluzioni così tante volte che ho pensato di chiedere se ci sono tecniche formali e forse componenti Delphi che potrebbero migliorare o semplificare il mio codice. Sto per passare al codice multithread che rende la domanda ancora più rilevante per me.Qual è il modo preferito del codice server per notificare a più client le modifiche ai dati all'interno di una singola applicazione Delphi?

Io uso due metodi:

  1. timestamp. Il codice 'server' mantiene un valore Int64 preso da QueryPerformanceCounter. I moduli client esaminano questo valore su un timer di spunta di 300 ms e si aggiornano se la loro copia del timestamp differisce da quella del server. Immagino che questa sia la mia soluzione 'pull'.

  2. Notifica di interfaccia. Il codice 'server' mantiene una classe derivata da TInterfaceList con i metodi AddClient e RemoveClient che registrano un'interfaccia notifcation client comune semplice. Ciascuno dei client si registra con questo elenco quando creato e si annulla su destroy. Le modifiche dei dati sul server attivano un'iterazione attraverso questo elenco, chiamando ogni cliente a consigliarlo di cambiare. Immagino che questa sia la mia soluzione 'push'.

amo le interfacce e la soluzione di 2 sembra bello dato che avoides timer ticchettio ed è facilmente il debug (anche se le chiamate Annulla registrazione può essere problematico con l'ordine di distruzione). Vi sono anche potenziali implicazioni sul rendimento perché è molto probabile che ci possano essere migliaia di cambiamenti di dati al secondo e devo fare attenzione a utilizzare un meccanismo BeginUpdate/EndUpdate per convertire le mie numerose modifiche dei dati del server in una vera e propria chiamata di notifica. Alla fine ho bisogno di un timer di qualche tipo per aggregare le chiamate in un aggiornamento delicato di un modulo visualizzato.

Entrambe le soluzioni funzionano bene e io sono combattuto tra i due. Per una soluzione multithread sono sicuro che ci sono altre insidie ​​di cui non so nulla. Qualsiasi commento sarebbe apprezzato. Sto usando XE2.

+2

+1 buona domanda. Sto usando il metodo 1 per la mia app client/server. – jpfollenius

+6

+1 Abbiamo adottato il secondo approccio. I client mantengono aperta la loro connessione, quando un client cambia qualcosa, altri client vengono notificati dal server, ogni cliente decide da solo se deve intervenire. –

+0

Ci sono open source [message broker] (http://en.wikipedia.org/wiki/Message_broker) attorno al quale può trasmettere comandi o documenti a tutti i clienti che hanno 'aderito' a specifiche aree di interesse (chiamato 'Argomenti') , anche quando i clienti al momento non ascoltano. Questo modello di comunicazione di pubblicazione/sottoscrizione può essere utilizzato in Delphi con librerie client native. – mjn

risposta

8

è necessario prendere in considerazione ciò che si desidera che accada quando il numero di clienti cresce, poi decidere tra i due mali:

  • E 'ok se il mio prestazioni degradano pur essendo sicuro che tutti i dati siano in corso, sempre e ovunque nell'applicazione (quindi è necessario il modello di osservatore)
  • OK se i dati in alcuni punti sono in ritardo per migliorare le prestazioni (quindi è possibile utilizzare il polling e prolungare l'intervallo quando le iterazioni del poll causano troppo molto rallentamento)

Non sono un appassionato di sondaggi, perché di solito porta a soluzioni molto contorte (beh, almeno le cose che ho provato, forse l'ho fatto nel modo sbagliato allora).

Implementerei lo Observer Pattern in Delphi utilizzando le interfacce, è possibile utilizzare this o this come inizio.

+0

+1 e accettato per questo riferimento, che ha il codice demo e documenta la soluzione interfaccia ben: http : //itte.no/delphi/ObservedDemo.htm –

+0

@BrianFrost felice di essere di aiuto. –

1

Una utilizzato l'API di Windows per risolvere un problema simile a questo. Ma credo che il mio approccio sia più semplice. Nella mia domanda, l'evento non conosceva il numero di "clienti" e quali forme erano in realtà clienti.

Quello che ho fatto è:

  1. trasmettere un messaggio di Windows a tutte le forme aperte dalla mia applicazione (screen.forms[X]). Il messaggio include nel WParam un puntatore in un record che contiene informazioni su un evento. Inoltre, diverse azioni trasmettono messaggi distinti. WM_RECORDUPDATE per gli aggiornamenti DB, ad esempio.

  2. di Windows (client) ascoltare per il messaggio nel modo di:

    procedure RecordUpdateMessage(var msg: TMessage); message WM_RECORDUPDATE;

Procedura RecordUpdateMessage leggere il record puntato da msg.WParam e sulla base dei dati nei desides record se a reagire all'aggiornamento, inserire o eliminare un record nel DB.

+0

Sì, funziona e ho usato questa soluzione, ma manca di struttura e bisogna fare attenzione a documentare i messaggi. È l'equivalente di parlare con poche persone stando in un campo con un megafono! –