Architettura software del programma del controller hardware IoT con server HTTP incorporato

2

Sto solo provando a progettare un rapporto architettura / classe per il mio attuale progetto C ++ nel campo IoT.

Il programma stesso (controller) controlla vari componenti hardware tramite un dispositivo basato su braccio. Intendo utilizzare cpprestsdk per un'implementazione del server http che fornisce un'API per il programma client che consentirebbe di inviare al controller vari comandi ("accendi questo / quello", "stampami un registro", "riconfigura" e così via. .). Penso a cpprestsdk perché racchiude la comunicazione http, la gestione di json e coinvolge la libreria pplx per gestire compiti asincroni (ho lavorato con C # async / await e task in passato). Fornirebbe anche la possibilità di creare un'interfaccia web rapida e semplice per il dispositivo. Potrei sbagliarmi, ma questi sono i miei pensieri correnti.

Attualmente sto progettando un flusso di lavoro generale dell'applicazione e relazioni di classe di base.

Ho trovato il seguente:

    class App
    {
        Controller _controller; //wraps all hardware details, provides public methods to do something with the hardware
        Server _server; //wraps communication details
    };

    class Controller
    {
        void update(); //infinite loop - read inputs -> update variable -> set outputs. it runs on a background thread
        void switch(int deviceId, int state); //one of many methods to do something with the hardware
    };

    class Server
    {
    public:
        ...
    private:
        http_listener _listener; //cpprestsdk's server implementation

        handle_get(http_request request); //handles incoming requests, launches async tasks to handle these requests
        ...
    };

Ho pensato che il server dovrebbe nascondere tutto il codice di gestione HTTP dal resto dell'app per rendere il codice più pulito. Funzionerebbe bene, ma il problema è che _listener è quello che lancia effettivamente le attività asincrone quando arriva la richiesta.

Fondamentalmente, il mio problema è che dal punto di vista del design, Server non dovrebbe sapere nulla su Controller e viceversa. Permetterebbe di cambiare facilmente le loro implementazioni. Ma http_listener è colui che decide di avviare i thread in background, il che significa che è responsabile del controllo dell'intero flusso di lavoro (chiama i metodi di Controller , controlla i risultati, ecc ...) e con l'architettura corrente Controller non rientra nell'ambito di Server , figuriamoci http_listener (implementazione effettiva del server).

Potrei memorizzare tutte le richieste in una coda e gestirle una alla volta, ma ciò ucciderebbe tutti i vantaggi del modello asincrono.

L'altro problema che ho riscontrato è provare a rendere il ciclo di background infinito di Controller e le attività async di http_listener funzionano insieme. Il ciclo infinito (ciclo di scansione) per l'hardware gestito è una soluzione eccellente (ogni PLC funziona in questo modo), ma alcuni comandi potrebbero richiedere del tempo, il che significa che alcune attività asincrone (richieste) dovranno attendere il risultato più di un ciclo, interrogando i flag di Controller per determinare se l'esecuzione del comando è stata completata. Penso che possa portare a diversi problemi:

  • un sacco di meccanismi di blocco (mutex) che rallenterebbero il tempo di esecuzione del ciclo di scansione I / O.
  • attività zombie (thread in background) che attendono il risultato dei loro rispettivi comandi (sondaggio / controllo - non fanno quasi più nulla), ma conservano comunque la memoria.

Forse puoi vedere alcuni errori evidenti nel mio approccio? Forse potresti fornire un link / guida con le informazioni che possono rispondere alle mie domande?

P.S. Ora che ho finito di scrivere questo post, ho ancora più domande. = (

    
posta CorellianAle 08.12.2017 - 11:39
fonte

1 risposta

0

Basically, my problem is that from a design point of view, Server should not know anything about Controller and vice-versa.

Non puoi rendere l'App (o creare una nuova classe per questo) ricevere la richiesta http e reindirizzare al metodo del Controller appropriato? Questo termina l'accoppiamento tra Server e Controller.

The other problem I encountered is trying to make Controller's infinite background loop and http_listener's async tasks work together.

some commands may take some time, which means some async tasks(requests) will have to wait for the result more than one cycle

Potresti implementare quanto segue al fine di eliminare i problemi che hai descritto:

Server

  • [Server] riceve alcune richieste, ad esempio: switch (id, state);
  • [App] avvia SocketServer e avvia un "RunCommandThread", quindi termina;
  • [RunCommandThread] chiama Controller.switch (), registrando in esso alcuni callback per il risultato;
  • [Controller switch] invia un comando all'hardware e ritorna immediatamente (non attende il risultato);
  • [Controller IO scan loop] esegue la scansione di tutto; quando si esegue la scansione per il risultato specifico dello Switch, se la risposta è disponibile, chiama la richiamata registrata da qualcuno (RunCommandThread);
  • [RunCommandThread] il callback registrato scriverà il risultato nel SockerServer

Client

  • invia la richiesta HTTP per "switch";
  • crea una connessione socket a SocketServer nel server;
  • al termine del comando, il risultato verrà inviato tramite socket
risposta data 08.12.2017 - 12:45
fonte

Leggi altre domande sui tag