2012-01-18 9 views
5

私は、C#クライアントからTCPソケットを使ってJavaサーバーにファイルを転送しています。 C#クライアントでは、ファイルをバイト配列に変換して送信し、NetworkStreamを使用して送信します。JavaでC#バイト配列を読み取る

Javaサーバーでは、受信したバイト配列をファイルに変換するために次のコードを使用します。

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

     } 
} 

上記のコード受け取ったバイト配列は、Javaでプログラムされたクライアントから来ているが、C#のクライアントのためのコードは、DO-whileループbytesRead = input.read(...)メソッドでにハングアップします。場合は動作します

誰かが、この時点でC#クライアントではなくJavaクライアントでコードがハングしている理由を知っていますか? printlnメッセージの出力によれば、データはInputStreamによって確実に受信されており、bytesRead変数の初期化時に1回読み込まれますが、do-whileループ中は読み込まれません。

この問題を解決するための解決策または提案は歓迎されます。

ありがとうございます。

Midavi。基づいて

+2

私たちにあなたのC#コードを教えてください。おそらく 'Flush()'が欠けていますか? – dtb

+3

ファイルサイズが有効に送信されたデータ以下でない場合、read()はブロックされます。受信しようとしているデータのサイズを決して推測しないでください。ストリームが空になるまで読書を続ける必要があります。 – Viruzzo

答えて

0

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

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

は、あなたのバイトのデータはbyteArrayJARにalreadされたり、私がここにcompletly間違っていることを意味し、すべての利用可能なバイトを読み込み?

EDIT:

はちょうど私のプロジェクトのいくつかをチェックし...私は、Android < => C#のサーバーアプリケーションからデータを送信します。

私はあなたがC#の代わりにbyteからsbyteとして、あなたのバイトを送信する必要がString data = input.readLine();(ジャワ)と_sw.WriteLine("Testdata");(C#の)

+0

それも私が信じていることです。私が知っている限り、送信されるファイルがかなり大きければ、bytesReadが初期化された後に利用可能になるかもしれません。 do-whileループは、バイト配列全体がファイルに再構築される前に読み込まれるようにします。それとも私はこれが間違っていますか? – midavi

1

を使用しています。

さらに、do/whileループを通常のwhileループに変更する必要があります。最初のコールのストリームからinput.readまでのすべてのストリームをすでに読み込んでいる場合は、readが入力を待機するため、2番目のコールをブロックします。

+0

これはハングアップするものではありませんが、ある時点で問題になる可能性があります。 – user7116

+0

この問題を修正するまでは、バイナリデータが間違っているため、他の問題を確実に解決できなくなります。 –

+0

符号付きバイトは符号なしバイトと同じ幅であるため、表現の違いはソケットからの読み取りに影響しません。 OPの*現在の問題は他のところにあります。 – user7116

0

一般的なケースでは、事前に送信されているデータの量を知ることができないので、データをチャンクで受信し、より大きい配列へのオフセットを無視する方がよいでしょう。データが配列より大きい場合、または配列よりも小さい場合は、そのままのコードでは大文字と小文字をうまく処理できません。

はるかに単純なケースではcurrentByteオフセットを除去するために、次のようになります。

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

そして私は、クライアント側で、次のC#コードを使用:

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

クライアント側の結果:

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> 

サーバー側の結果:

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> 
関連する問題