2009-08-09 189 views
6

¿Cómo puede una aplicación C# comunicarse fácilmente con una instancia de sí misma presente en otra computadora, que está en la misma red, y transferir archivos y datos?¿Cómo puede una aplicación C# comunicarse y transferir archivos en una red fácilmente?

Suponiendo que las computadoras en la red tienen direcciones IP locales fijas, y que cada uno conoce las direcciones IP de los demás. ¿También habría una forma de comunicarse si las IP son desconocidas? basado en algún protocolo de descubrimiento?

Escuché que el servicio "Bonjour" de Apple era un buen protocolo. ¿Podemos comunicarnos desde nuestras aplicaciones de Windows? O tienes que usar "sockets". Principalmente busco bibliotecas o código de muestra que pueda satisfacer mis necesidades fácilmente, ¡no quiero desarrollar mi propio protocolo basado en TCP ni nada de hardcore!

Respuesta

2

Para transferir los archivos/datos, puede usar las clases TcpClient/TcpListener, que son buenas abstracciones sobre la funcionalidad de socket más grittier. O bien, podría simplemente tener la aplicación como un servidor HTTP utilizando la clase HttpListener, si eso es más fácil/más apropiado para su aplicación.

Para descubrimiento, si puede tener un servidor central; luego, puede hacer que cada cliente se conecte con el servidor al inicio, registrarse y recuperar una lista de otros clientes en línea y sus IP. La comunicación posterior puede tener lugar directamente entre los clientes.

Una variación de este esquema, es permitir que el servidor central actúe como un proxy, que atraviesa todo el tráfico entre los clientes. Esto sería de gran ayuda para superar los problemas de firewall o enrutamiento si los clientes no están en la misma red (por lo que no es necesario para su escenario).

+0

ASP.Net classes? Estaba buscando comunicación entre las aplicaciones de Windows. –

+0

¿Qué quieres decir? Ninguna de las clases que menciono son clases ASP .NET. – driis

2

La gran cosa acerca de los archivos y sockets en C# es que los dos están expuestos como corrientes. Copiar un archivo grande de una secuencia a otra es bastante simple:

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

A continuación, sólo cierra el socket cuando haya terminado.

Si desea enviar metadatos (nombres de archivo, tamaños) o no desea cerrar la conexión, necesita algún tipo de protocolo para manejar esto. FTP utiliza dos sockets separados (uno para metadatos, uno para datos, esto se llama comunicación fuera de banda). Si estás en una LAN sin firewalls, eso puede ser perfectamente aceptable. Por otro lado, si desea hacer una transferencia de Internet, abrir un solo puerto es una tarea difícil y dos es insoportable. Si no le importa demasiado el rendimiento, puede codificar los bytes en la codificación base64, lo que garantiza que estén dentro de un determinado rango de bytes. Con base64, puede separar mensajes con líneas nuevas u otros caracteres no alfanuméricos. Luego, en el primer mensaje incluya el nombre de archivo, el tamaño o lo que sea, luego envíe los datos como un segundo mensaje, luego envíe un mensaje de "ese es todo el archivo" para que el cliente sepa que ya está hecho.

Otra táctica para los mensajes es utilizar una secuencia de escape. Por ejemplo, tome su bytestream y reemplace cada instancia de '\ 0' con '\ 0 \ 0'. Ahora use '\ 0 \ 1' para señalar el final del mensaje, que está garantizado que no está contenido en su mensaje de datos. Decodifique el '\ 0 \ 0' de nuevo a '\ 0' en el extremo receptor.Esto funciona bastante bien en C, pero me parece que, en la práctica, el bucle a través de cada byte puede ser más lento que la lectura de búferes enteros en C#.

La mejor manera es adoptar algún tipo de protocolo de longitud adaptable. Por ejemplo, envíe los datos en trozos de un cierto tamaño (digamos 512 bytes). Antes de cada fragmento, envíe un int de 32 bits que represente el tamaño del fragmento mediante System.BitConverter. Para que los mensajes se ven así (Inglés):

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

La ventaja aquí es que se puede realizar la copia/leen amortiguadores funcionan para usted (la lectura de 512 bytes a la vez), es decir, su rendimiento está limitado por su pila de red en lugar de tu código C#. El cliente lee el int de 32 bits de longitud fija que le permite conocer el tamaño del buffer que debe usar para el siguiente segmento de [datos].

Aquí hay algo de código para escribir mensajes como que:

 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(); 

Y aquí hay un código para leerlos:

   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; 
Cuestiones relacionadas