2011-02-02 5 views
6

Ho bisogno di creare un'applicazione linux che faccia la scansione della rete wireless, metti il ​​risultato in una struttura e lo invii in qualche modo a un'altra applicazione principale che userà i dati. La mia idea iniziale era di creare una pipe nell'applicazione principale, fork e avviare un altro processo da execl, che può scrivere sulla pipe. Qualcosa di simile a questo:Come scambiare dati binari tra processi in Linux

pid_t pid = NULL; 
int pipefd[2]; 
FILE* output; 
char line[256]; 

pipe(pipefd); 
pid = fork(); 
if (pid == 0) 
{ 
// Child 
    close(pipefd[0]); 
    dup2(pipefd[1], STDOUT_FILENO); 
    dup2(pipefd[1], STDERR_FILENO); 
    execl("/sbin/wifiscan", "/sbin/wifiscan", (char*) NULL); 
} 

//Only parent gets here. Listen to what the wifi scan says 
close(pipefd[1]); 
output = fdopen(pipefd[0], "r"); 

while(fgets(line, sizeof(line), output)) 
{ 
//Here we can listen to what wifiscan sends to its standard output 
} 

Questo però non funziona con dati binari, se binarie 0 appare nell'output. Così ho potuto sia formattare l'output dell'applicazione wifiscan in testo, inviarlo a pipe e analizzare nell'applicazione principale, o farlo in modo più intelligente che non conosco ancora.

Quali sono altri modi per scambiare dati in modo affidabile tra processi in Linux?

risposta

7

ho il sospetto quello che sta succedendo è che fgets() sta leggendo i caratteri NUL correttamente, ma si sta interpretando il primo come la fine della linea che è stato letto. È difficile perché fgets() è destinato all'input testuale e usa "\ 0" come sentinella, non restituendo il numero di caratteri letti. Anche se si sa che ogni riga sarà terminata con \n, c'è la possibilità che i dati binari non elaborati incorporati in una riga includano anche uno \n. Quindi, passare a fread(), che è pensato per binario. È possibile inserire una dimensione del messaggio a lunghezza fissa (ad es. 2 byte, 4 byte) nella parte anteriore di ciascun messaggio in modo che l'altro lato possa leggerlo prima, quindi fare un fread() per la dimensione esatta del messaggio, evitando problemi di messaggistica parziale .

Se davvero desidera mantenere qualche strano ibrido di testo e binari, si potrebbe provare a utilizzare ftell() dopo fgets() per scoprire quanto più lungo il torrente si è, e quindi il numero di caratteri dovrebbe essere nel buffer , ma non ho mai visto un sistema serio fare qualcosa di così hacky.

Per la registrazione, senza fare qualcosa di marcatamente inefficiente come la codifica esadecimale di ogni singolo carattere nei dati binari, si potrebbe semplicemente codificare il/i carattere/i problematico/i. Ad esempio, è possibile utilizzare le sequenze di escape letterali C stringa, con \0 che rappresenta un NUL e \\ un singolo \. Sebbene sia meno facile da controllare visivamente, potrebbe essere più facile programmare a livello di codice/decodificare i caratteri non stampabili usando ottale \NNN. Se ci sono molti caratteri non stampabili, allora un approccio uuencode in base 64 - come quello usato negli allegati e-mail MIME - è un'altra codifica adatta, ma totalmente non leggibile.

+1

'ftell()' è improbabile che lavorare sui flussi unseekable come i tubi, in ogni caso. – caf

+0

Sono d'accordo con la costruzione di un protocollo di base per i dati e quindi utilizzando 'fread()' invece di 'fgets()'. Questo [risposta] (http://stackoverflow.com/questions/2870549/fifos-implementation/2871538#2871538) ad una domanda sul [implementazione FIFO] (http://stackoverflow.com/q/2870549/203667) potrebbe essere di ulteriore utilizzo in quanto fornisce un paio di esempi su come un tale protocollo potrebbe essere eseguito. – jschmier

+0

fread() funziona perfettamente. Grazie – Patryk

0

scambiare dati in modo affidabile? Questo mi fa pensare alla libreria 0MQ (ZeroMQ): http://zeromq.org

Dai un'occhiata, e come bonus i tuoi processi saranno in grado di parlare anche su computer distanti.

Benvenuti nel cloud.

2

Normalmente uno utilizza fread e fwrite per scambiare le strutture binarie tra i processi. Funziona alla grande per i record di lunghezza fissa, e non ci sono problemi nell'invio di null, ecc.

ho trovato sulla mia lunga carriera che nella maggior parte delle applicazioni è molto meglio per lo scambio di stringhe ASCII, facile da interpretare (ad esempio scanf), invece di dati binari. In questo modo i messaggi possono essere osservati e registrati, e i singoli processi possono essere testati tramite telnet e digitando (solitamente incollando) su di essi. Semplifica lo sviluppo se il programmatore può solo leggere il traffico dei messaggi.