2012-01-18 19 views
5

Estoy transfiriendo un archivo de un cliente C# a un servidor Java utilizando sockets TCP. En el cliente C#, convierto el archivo a una matriz de bytes para su transmisión y lo envío utilizando un NetworkStream.Lectura de una matriz de bytes C# en Java

En el servidor Java utilizo el siguiente código para convertir la matriz de bytes recibida de nuevo en un archivo;

public void run() { 

     try { 

      byte[] byteArrayJAR = new byte[filesize]; 
      InputStream input = socket.getInputStream(); 

      FileOutputStream fos = new FileOutputStream(
        "Controller " + controllerNumber + ".jar"); 

      BufferedOutputStream output = new BufferedOutputStream(fos); 

      int bytesRead = input.read(byteArrayJAR, 0, byteArrayJAR.length); 
      int currentByte = bytesRead; 

      System.out.println("BytesRead = " + bytesRead); 

      do { 

       bytesRead = input.read(
         byteArrayJAR, 
         currentByte, 
         (byteArrayJAR.length - currentByte)); 

       if (bytesRead >= 0) { 

        currentByte += bytesRead; 

       } 
      } 

      while (bytesRead > -1); 

      output.write(byteArrayJAR, 0, currentByte); 
      output.flush(); 
      output.close(); 
      socket.close(); 

     } 

     catch (IOException e) { 

      e.printStackTrace(); 

     } 
} 

El código anterior funciona si la matriz de bytes recibido proviene de un cliente programado con Java, pero para C# clientes el código pende de un do-while en el BytesRead = input.read método (...).

¿Alguien sabe por qué el código está colgado en este punto para un cliente C# pero no para un cliente Java? De acuerdo con la salida del mensaje de impresión, los datos son recibidos por InputStream y se leen una vez en la inicialización de la variable bytesRead, pero no durante el ciclo do-while.

Cualquier solución o sugerencia para superar este problema sería bienvenida.

Saludos,

Midavi.

+2

Muéstrenos su código C#. ¿Te estás perdiendo un 'Flush()'? – dtb

+3

Si filesize no es menor o igual que los datos enviados de manera efectiva, read() bloqueará. Nunca intentes adivinar el tamaño de los datos que vas a recibir, debes seguir leyendo hasta que la transmisión esté vacía. – Viruzzo

Respuesta

0

Basado en: http://docs.oracle.com/javase/1.4.2/docs/api/java/io/InputStream.html

int bytesRead = input.read(byteArrayJAR, 0, byteArrayJAR.length); 

lee todos los bytes disponibles que significa que su byte de datos se Alread en byteArrayJAR o estoy completamente mal aquí?

EDIT:

acaba de comprobar algunos de mis proyectos ... Me enviar datos desde Android < => C# aplicación de servidor.

utilizo String data = input.readLine(); (Java) y _sw.WriteLine("Testdata"); (C#)

+0

Eso es lo que creo también. Por lo que sé, si el archivo que se envía es bastante grande, más bytes pueden estar disponibles después de inicializar bytesRead. El bucle do-while está allí para asegurarse de que todo el conjunto de bytes se lee antes de reconstruirse en un archivo. ¿O tengo esto mal? – midavi

1

Es necesario enviar sus bytes como sbyte de C# en lugar de byte.

Además, debe cambiar su ciclo do/while a un ciclo while normal. Si ya ha leído todo el contenido de la transmisión en su primera llamada al input.read, bloqueará en la segunda llamada porque read esperará la entrada.

+0

Eso no debería hacer que se cuelgue, pero puede ser un problema en algún momento. – user7116

+0

hasta que solucione ese problema, no podrá resolver de manera confiable ningún otro problema debido a que los datos binarios están equivocados. –

+0

Un byte con signo tiene el mismo ancho que un byte sin signo, por lo tanto, la diferencia en la representación no afectará la lectura del socket. El problema * actual del OP está en otra parte. – user7116

0

Dado que no puede saber la cantidad de datos que se envían por adelantado en el caso general, sería mejor recibir los datos en fragmentos e ignorar el desplazamiento en su matriz más grande. Su código tal como está no maneja muy bien el caso si los datos son más grandes que su matriz, ni si son más pequeños que la matriz.

Un caso mucho más simple sería la de eliminar el currentByte offset:

InputStream input = socket.getInputStream(); 
BufferedOutputStream output = new BufferedOutputStream(
    new FileOutputStream("test.exe")); 

byte[] bytes = new byte[2048]; 
int bytesRead; 
do { 
    bytesRead = input.read(bytes, 0, bytes.length); 
    System.out.println("size: " + bytes.length + " read(): " + bytesRead); 

    if (bytesRead > 0) { 
     output.write(bytes, 0, bytesRead); 
    } 
} while (bytesRead > -1); 

output.close(); 
socket.close(); 
input.close(); 

Y utilizado el siguiente código C# en el lado del cliente:

if (!args.Any()) 
{ 
    Console.Error.WriteLine("Usage: send.exe <executable>"); 
    Environment.Exit(-1); 
} 

using (var client = new TcpClient("localhost", 10101)) 
using (var file = File.Open(args.First(), FileMode.Open, FileAccess.Read)) 
{ 
    file.CopyTo(client.GetStream()); 
} 

resultados lado del cliente:

C:\temp>csc send.cs 
Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1 
Copyright (C) Microsoft Corporation. All rights reserved. 


C:\temp>send send.exe 

C:\temp> 

Resultados secundarios del servidor:

C:\temp>javac.exe Server.java 

C:\temp>java Server 
size: 2048 read(): 2048 
size: 2048 read(): 2048 
size: 2048 read(): 512 
size: 2048 read(): -1 

C:\temp>test.exe 
Usage: send.exe <executable> 
Cuestiones relacionadas