2009-08-09 8 views
6

In che modo un'app C# può comunicare facilmente con un'istanza di sé presente su un altro computer, che si trova sulla stessa rete, e trasferire file e dati?Come può un'app C# comunicare e trasferire facilmente file su una rete?

Supponendo che i computer sulla rete abbiano indirizzi IP locali fissi, si conoscono reciprocamente gli IP. Ci sarebbe anche un modo per comunicare se gli IP sono sconosciuti? basato su qualche protocollo di scoperta?

Ho sentito che il servizio "Bonjour" di Apple era un buon protocollo. Possiamo comunicare tramite esso dalle nostre app Windows? O devi usare "prese". Sono principalmente alla ricerca di librerie o codice di esempio in grado di soddisfare facilmente le mie esigenze, non voglio sviluppare il mio protocollo basato su TCP o qualcosa di hardcore!

risposta

2

Per il trasferimento di file/dati, è possibile utilizzare le classi TcpClient/TcpListener, che è una bella astrazione sulla funzionalità del socket gritoso. Oppure, potresti semplicemente avere l'applicazione come server HTTP usando la classe HttpListener, se è più facile/più appropriata per la tua applicazione.

Per la scoperta, se si è in grado di avere un server centrale; quindi è possibile che ogni client si connetta al server all'avvio, per registrarsi e recuperare un elenco di altri client online e dei relativi IP. La comunicazione successiva può quindi avvenire direttamente tra i client.

Una variante di questo schema è di consentire al server centrale di agire come un proxy, attraverso il quale scorre tutto il traffico tra i client. Ciò sarebbe di grande aiuto per superare i problemi di firewall o routing se i client non si trovano sulla stessa rete (quindi non è probabilmente necessario per lo scenario).

+0

Classi ASP.Net? Stavo cercando una comunicazione tra le app di Windows. –

+0

Cosa intendi? Nessuna delle classi che menziono sono classi ASP .NET. – driis

2

La cosa grandiosa di file e le prese in C# è che sono entrambi esposti come flussi. Copiare un file di grandi dimensioni da uno stream a un altro è piuttosto semplice:

byte[] data = new byte[1024]; 
while(true) { 
int bytesRead = filestream.read(data,0,data.Length); 
if (bytesRead==0) break; 
netstream.write(data,0,bytesRead); 
} 

Quindi basta chiudere lo zoccolo quando hai finito.

Se si desidera inviare metadati (nomi di file, dimensioni) o non si desidera chiudere la connessione, è necessario un qualche tipo di protocollo per gestirlo. FTP utilizza due socket separati (uno per i metadati, uno per i dati, chiamato comunicazione out-of-band). Se sei su una LAN senza firewall, ciò può essere perfettamente accettabile. D'altra parte, se si desidera effettuare il trasferimento su Internet, ottenere una singola porta aperta è un'attività abbastanza difficile, e due sono insopportabili. Se non ti preoccupi troppo delle prestazioni, potresti codificare i byte nella codifica base64, il che assicura che siano all'interno di un certo intervallo di byte. Con base64, puoi separare i messaggi con newline o altri caratteri non alfanumerici. Quindi nel primo messaggio includi il nome file, la dimensione o qualsiasi altra cosa, quindi invia i dati come un secondo messaggio, quindi invia un messaggio "questo è l'intero file" in modo che il client sappia che è fatto.

Un'altra tattica per i messaggi è l'utilizzo di una sequenza di escape. Per esempio, prendi il tuo puntatore e sostituisci ogni istanza di '\ 0' con '\ 0 \ 0'. Ora usa '\ 0 \ 1' per segnalare la fine del messaggio, che è garantito non essere contenuto nel tuo messaggio di dati. Decodificare '\ 0 \ 0' su '\ 0' sul lato ricevente.Funziona abbastanza bene in C, ma trovo che, in pratica, il looping di ogni byte può essere più lento della lettura di interi buffer in C#.

Il modo migliore è adottare una sorta di protocollo di lunghezza adattiva. Ad esempio, invia i dati in blocchi di una certa dimensione (ad esempio 512 byte). Prima di ogni blocco, invia un int a 32 bit che rappresenta la dimensione del blocco tramite System.BitConverter. Così i messaggi appaiono così (inglese):

Here's 512 bytes: 
[data] 
Here's 512 bytes: 
[data] 
Here's 32 bytes: 
[data] 
Here's 4 bytes: 
That was the whole file 

Il vantaggio è che si può fare la copia/lettura buffer di lavoro per voi (la lettura di 512 byte alla volta), il che significa la velocità effettiva è limitata dal tuo stack di rete invece del tuo codice C#. Il client legge l'int a 32 bit a lunghezza fissa che gli consente di conoscere la dimensione del buffer che dovrebbe utilizzare per il prossimo segmento [dati].

Ecco il codice per scrivere i messaggi del genere:

 logger.logger.debug("Sending message of length " + length); 
     byte[] clength = System.BitConverter.GetBytes(buffer.Length); 
     plaintextStream.Write(clength,0,clength.Length); 
     plaintextStream.Write(buffer,0,buffer.Length); 
     plaintextStream.Flush(); 

Ed ecco un po 'di codice per leggere loro:

   byte[] intbuf = new byte[int_32_size]; 
     int offset = 0; 
     while (offset < int_32_size) 
     { 
      int read = 0; 

      read = d.plaintextStream.Read(intbuf,offset,int_32_size - offset); 
      offset += read; 

     } 
     int msg_size = System.BitConverter.ToInt32(intbuf,0); 
     //allocate a new buffer to fill the message 
     byte[] msg_buffer = new byte[msg_size]; 
     offset = 0; 
     while (offset < msg_size) 
     { 
      int read = 0; 

      read = d.plaintextStream.Read(msg_buffer,offset,msg_size - offset); 
      offset += read; 
     } 


     return msg_buffer; 
Problemi correlati