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;
ASP.Net classes? Estaba buscando comunicación entre las aplicaciones de Windows. –
¿Qué quieres decir? Ninguna de las clases que menciono son clases ASP .NET. – driis