Questo è il secondo progetto a cui sto lavorando e che utilizzerà un design di cui non sono sicuro al 100%. Vorrei ricevere feedback, forse suggerimenti per un design migliore, o verificare che ciò sia accettabile dai programmatori più esperti:
Ho un dispositivo con cui mi devo interfacciare. Sia via TCP, UART, UDP, o qualsiasi altra cosa. Devo inviare questo dispositivo dati / controllo e ricevere dati / informazioni di controllo da questo dispositivo, ma non è esattamente una sorta di situazione richiesta / risposta. Il dispositivo può inviare dati in momenti casuali senza lo stimolo dell'utente. Ad esempio, il dispositivo più recente è una radio full-duplex. Quando la radio demodula e decodifica correttamente i pacchetti digitali, invierà i dati vocali tramite UDP alla mia libreria. Non aspetta un utente per l'input. Quando si desidera inviare materiale via etere, invio le informazioni di controllo e quindi i dati per la radio per modulare e spingere in aria.
I pacchetti che vanno tra la mia libreria e il dispositivo sono incorniciati: cioè, ogni pacchetto viene anteposto a un'intestazione (e ad altri metadati per identificare il tipo di pacchetto) e aggiunto un CRC e un piè di pagina quindi conosco a) l'inizio di un pacchetto nel caso in cui la spazzatura sia in qualche modo introdotta sullo stream e b) i dati siano corretti (verificando il piè di pagina e il CRC corretto).
Ok, quindi sto progettando una libreria che dovrà essere consegnata a uno sviluppatore diverso per lo sviluppo di applicazioni. Quindi tutti gli interni sono lontani da lui. Per semplicità in questo esempio, voglio che questa libreria abbia 4 chiamate: send_data, receive_data, send_voice, receive_voice. I diversi tipi di pacchetti (voce e dati) vengono inviati su una porta. La libreria può inquadrare e analizzare i pacchetti appropriati (rispettivamente per l'invio e la ricezione) e il dispositivo.
Per l'invio di dati al dispositivo:
Questo è facile.
Lo sviluppatore dell'applicazione chiama send_data
o send_voice
. Prendo la voce o i dati rilevanti, li inquadrano di conseguenza e li invio al dispositivo. Il dispositivo analizza i dati e li invia per la sua strada. Le chiamate sono thread-safe, quindi lo sviluppatore non può richiamare l'UDP in modo asincrono.
Per ricevere dati dal dispositivo:
Questo è dove non sono sicuro al 100% nel design.
Avvio di un thread di ricezione (RX) nella mia libreria. Quando ottengo un pacchetto (voce o dati), de-frame il pacchetto e metto la voce oi dati su una rispettiva coda (una coda vocale e una coda dati).
Quando lo sviluppatore dell'applicazione vuole la voce, chiama receive_voice
e restituirà un pop dalla coda vocale. Quando lo sviluppatore dell'applicazione desidera i dati, chiama receive_data
e restituirà un pop dalla coda dei dati.
Ovviamente sto attento che le code non possano crescere all'infinito, e quando una coda è MAX_QUEUE_LEN
, metto un pacchetto vocale / dati fuori dalla coda e lo scartano prima di metterne uno nuovo, e imposta un flag 'overrun' . Questo flag può essere impostato / letto con set_X_overrun
o get_X_overrun
, dove X è vocale o dati dipendenti dalla coda.
In realtà mi piace il design. Tuttavia, cosa pensano le altre persone? Non sono sicuro di cosa la gente pensi di inserire un thread in esecuzione all'interno di una libreria? Immagino che l'altra opzione sia quella di avere solo read_data
e read_voice
chiamate che bloccherà fino a quando non verrà trovato un pacchetto che corrisponde a quello che vogliono (voce o dati). Ciò elimina la necessità di un thread in esecuzione, ma in questo caso il pacchetto opposto viene essenzialmente ignorato mentre attendiamo quello di scelta. O c'è un altro progetto a cui non sto nemmeno pensando?
Ci scusiamo per la domanda di design prolisso e probabilmente poco chiara. Ora che mi sento più un programmatore fiducioso che usa la semantica / sintassi dei linguaggi stessi, mi sto interessando molto di più alla progettazione di programmi piuttosto che al nocciolo delle chiamate di livello inferiore. Sto cercando il design migliore / più bello possibile piuttosto che qualcosa che "funziona".
Punti bonus se esiste una sorta di software open source che posso esaminare e migliorare il mio design.
Immagine del design:
]
Pseudocodice:
public void send_data(buf) {
frame_data_packet(buf);
udp_send(buf);
}
public void send_voice(buf) {
frame_voice_packet(buf);
udp_send_(buf);
}
public void receive_data(buf) {
buf = data_queue.pop();
}
public void receive_voice(buf) {
buf = voice_queue.pop();
}
/* RX Thread */
public void run_rx()
{
while (run_rx_f) {
type = deframe_data(data);
switch (type) {
case VOICE:
voice_queue.add(data);
break;
case DATA:
data_queue.add(data);
break;
}
}
}