2012-01-18 14 views
5

Sto trasferendo un file da un client C# a un server Java tramite TCP Sockets. Nel client C# converto il file in un array di byte per la trasmissione e lo invio utilizzando un NetworkStream.Lettura di un array di byte C# in Java

Sul server Java utilizzo il seguente codice per convertire nuovamente l'array di byte ricevuto in un file;

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

     } 
} 

Il codice precedente funziona se l'array di byte ricevuto proviene da un client programmato con Java, ma per C# client il codice si blocca in do-while metodo anello nella parte bytesRead = input.read (...).

Qualcuno sa perché il codice è sospeso a questo punto per un client C# ma non un client Java? Secondo l'output dal messaggio println, i dati vengono definitivamente ricevuti da InputStream e letti una sola volta all'inizializzazione della variabile Bytes Read, ma non durante il ciclo do-while.

Qualsiasi soluzione o suggerimento per superare questo problema sarebbe il benvenuto.

Saluti,

Midavi.

+2

Mostraci il tuo codice C#. Ti manca forse un 'Flush()'? – dtb

+3

Se il file non è inferiore o uguale ai dati effettivamente inviati, read() si bloccherà. Non dovresti mai cercare di indovinare la dimensione dei dati che stai per ricevere, devi continuare a leggere finché lo stream non è vuoto. – Viruzzo

risposta

0

basa su: http://docs.oracle.com/javase/1.4.2/docs/api/java/io/InputStream.html

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

legge tutti i byte disponibili significa che il byte di dati viene alread in byteArrayJAR o sono io completamente sbagliato qui?

EDIT:

appena controllato alcuni dei miei progetti ... io mando i dati da Android < => C# Application Server.

Io uso String data = input.readLine(); (java) e _sw.WriteLine("Testdata"); (C#)

+0

Questo è quello che credo anch'io. Per quanto ne so, se il file che si sta inviando è abbastanza grande, potrebbero essere disponibili più byte dopo l'inizializzazione di bytesRead. Il ciclo do-while è lì per assicurarsi che l'intero array di byte venga letto prima di essere ricostruito in un file. O ho sbagliato? – midavi

1

È necessario inviare i byte come sbyte da C#, invece di byte.

Inoltre, è necessario modificare il ciclo di do/while in un ciclo normale. Se hai già letto tutto dallo stream durante la prima chiamata a input.read, bloccherai la seconda chiamata perché read attenderà l'input.

+0

Ciò non dovrebbe causare il blocco, ma potrebbe essere un problema ad un certo punto. – user7116

+0

finché non risolvi il problema, non sarai in grado di risolvere in modo affidabile altri problemi a causa del fatto che i dati binari sono errati. –

+0

Un byte con segno ha la stessa larghezza di un byte senza segno, quindi la differenza di rappresentazione non ha effetto sulla lettura dal socket. Il problema * attuale * dell'OP si trova altrove. – user7116

0

Poiché non è possibile conoscere la quantità di dati inviati in anticipo nel caso generale, sarebbe meglio ricevere i dati in blocchi e ignorare l'offset nell'array più grande. Il tuo codice così com'è non gestisce il caso molto bene se i dati sono più grandi dell'array, né se sono più piccoli dell'array.

Un caso molto più semplice sarebbe quella di rimuovere il 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(); 

E ho usato il seguente codice C# sul lato client:

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

risultati lato client:

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> 

Risultati lato server:

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> 
Problemi correlati