2012-01-18 40 views
5

Tôi đang chuyển một tệp từ máy khách C# sang máy chủ Java bằng cách sử dụng TCP Sockets. Trên máy khách C# tôi chuyển đổi tệp thành mảng byte để truyền và gửi nó bằng cách sử dụng NetworkStream.Đọc một mảng C# byte trong Java

Trên máy chủ Java, tôi sử dụng mã sau để chuyển đổi mảng byte đã nhận trở lại thành tệp;

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

     } 
} 

Đoạn mã trên hoạt động nếu mảng byte nhận được xuất phát từ một khách hàng được lập trình với Java nhưng đối với C# khách hàng mã treo trong do-while loop tại bytesRead = input.read phương pháp (...).

Có ai biết tại sao mã được treo tại thời điểm này cho một khách hàng C# nhưng không phải là một khách hàng Java? Theo đầu ra từ dữ liệu tin nhắn println là chắc chắn được nhận bởi InputStream và được đọc một lần tại khởi tạo biến bytesRead, nhưng không phải trong vòng lặp do-while.

Bất kỳ giải pháp hoặc đề xuất nào để khắc phục sự cố này đều được hoan nghênh.

Trân trọng,

Midavi.

+2

Hiển thị cho chúng tôi mã C# của bạn. Bạn có lẽ thiếu một 'Flush()'? – dtb

+3

Nếu các tập tin không nhỏ hơn hoặc bằng dữ liệu được gửi một cách hiệu quả, hãy đọc() sẽ chặn. Bạn không bao giờ nên thử đoán kích thước của dữ liệu bạn sẽ nhận được, bạn phải tiếp tục đọc cho đến khi luồng trống. – Viruzzo

Trả lời

0

Dựa trên: http://docs.oracle.com/javase/1.4.2/docs/api/java/io/InputStream.html

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

Đọc tất cả các byte có sẵn mà có nghĩa là byte dữ liệu của bạn được alread trong byteArrayJAR hay tôi hoàn toàn sai ở đây?

EDIT:

Chỉ cần kiểm tra một số dự án của tôi ... Tôi gửi dữ liệu từ thiết bị Android < => C# Application Server.

tôi sử dụng String data = input.readLine(); (java) và _sw.WriteLine("Testdata"); (C#)

+0

Đó cũng là điều tôi tin. Theo như tôi biết nếu tập tin được gửi là khá nhiều byte hơn có thể trở nên có sẵn sau khi byteRead được khởi tạo. Vòng lặp do-while nằm ở đó để đảm bảo toàn bộ mảng byte được đọc trước khi được xây dựng lại thành một tệp. Hay tôi có điều này sai? – midavi

1

Bạn cần gửi byte của bạn như sbyte từ C# thay vì byte.

Ngoài ra, bạn nên thay đổi vòng lặp do/while thành vòng lặp thông thường. Nếu bạn đã đọc mọi thứ từ luồng trong cuộc gọi đầu tiên của bạn đến input.read thì bạn sẽ chặn cuộc gọi thứ hai vì read sẽ đợi đầu vào.

+0

Điều đó không nên khiến nó bị treo, nhưng có thể là một vấn đề tại một số điểm. – user7116

+0

cho đến khi bạn khắc phục sự cố đó, bạn sẽ không thể giải quyết một cách đáng tin cậy bất kỳ vấn đề nào khác do dữ liệu nhị phân bị sai. –

+0

Một byte đã ký có chiều rộng tương tự như một byte chưa ký, do đó, sự khác biệt về biểu diễn sẽ không ảnh hưởng đến việc đọc từ socket. Vấn đề * hiện tại * của OP nằm ở nơi khác. – user7116

0

Vì bạn không thể biết số lượng dữ liệu được gửi trước trong trường hợp chung, sẽ tốt hơn nếu nhận dữ liệu theo khối và bỏ qua phần bù vào mảng lớn hơn của bạn. Mã của bạn as-is không xử lý trường hợp rất tốt nếu dữ liệu lớn hơn mảng của bạn, cũng không phải nếu nó nhỏ hơn mảng.

Một trường hợp đơn giản hơn nhiều sẽ là để loại bỏ các 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(); 

Và tôi đã sử dụng mã # C sau trên các mặt hàng:

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

phía khách hàng kết quả:

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> 

Kết quả bên phía máy chủ:

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> 
Các vấn đề liên quan