Protocolli applicativi e macchine a stati: progettazione di un server complicato

3

Sto progettando e prototipando un server con le seguenti caratteristiche:

  • durante l'inizializzazione del demone esso genera nove server "manager", ognuno dei quali risolve una parte del problema complessivo.
  • dopo l'inizializzazione, il daemon accetta le connessioni dai client, creando un server "slave" per ciascuno che si connette ai gestori e quindi accetta le richieste dal client, le distribuisce ai gestori, assembla i risultati e li rimanda a il client, ad infinitum.
  • il daemon, i gestori e gli slave dovrebbero avere la capacità di accettare contemporaneamente le connessioni "di controllo" da un terminale e ricevere ed elaborare i comandi (ad es. query per le statistiche sulle prestazioni).
  • la concorrenza di I / O socket di ciascun processo è gestita da select ().

Il problema che sto affrontando è la complessità della codifica. Per prima cosa, ogni programma ha almeno due fasi - inizializzazione e ciclo principale - in cui stabilisce in vario modo una connessione al suo genitore, o accetta una connessione dai suoi figli, o invia e attende in modo asincrono i suoi figli, e così via . In vari punti non voglio, ad esempio, accettare una connessione client mentre sto inizializzando, o voglio accettare sessioni di controllo anche nel corso di un'elaborazione regolare. Per non parlare della gestione del protocollo di ciascuna di queste connessioni.

Dato abbastanza tempo, probabilmente potrei massaggiare tutto questo in un insieme di chiamate di subroutine ragionevolmente ben fatto. Ma ricordo di aver sentito parlare di un approccio completamente diverso a questo tipo di problema, che coinvolge libevent, callback e macchine a stati finiti.

Quello che spero è che qualcuno che legge questo potrebbe dire "Perché, sì! Questo è un perfetto esempio di dove callback di eventi e FSM sono di gran lunga superiori al loop su select () s - e un ottimo articolo introduttivo su questo è. .. "o" ecco di cosa si tratta in breve ". (O, forse, "non è per niente quello che è destinato a libevent.")

    
posta Chap 17.01.2013 - 06:35
fonte

1 risposta

5

Non ci sono proiettili d'argento nel design o nell'architettura. ( Mi spiace )

Sembra che tu sia ancora agli inizi della fase di progettazione e penso che tu debba concentrarti maggiormente sugli aspetti "divide et impera" della mappatura della tua applicazione. Correre nei dettagli di livello inferiore prima di avere un design completo significa che potresti perdere opportunità "ovvie" per tecniche particolari. Completo non significa final significa solo che hai tutti i componenti principali e le loro interazioni disposte in una forma generale. In altre parole, devi sapere dove stai cercando di andare prima che tu possa arrivarci.

Una volta che hai mappato i principali requisiti del demone, dei gestori e dei processori (slave), dovresti iniziare a esaminare quali requisiti / funzioni sono consentite in quali fasi. Questo porterà nelle tue definizioni di stato e quegli stati dovrebbero aiutare a perfezionare l'ambito del programma.

Dovresti anche essere in grado di identificare i componenti comuni in base alle funzioni e ai requisiti. Combinato con le definizioni di stato di prima, è possibile determinare quando è possibile chiamare componenti comuni e con quali parametri. Ancora una volta, questo dovrebbe aiutare a ridurre le dimensioni del tuo programma.

È a questo punto che puoi considerare le code, i callback, ecc. in base a ciò che il tuo progetto richiede che il programma faccia. Prototipo di alcuni e poi torna indietro e perfeziona il design.

    
risposta data 17.01.2013 - 15:49
fonte