2013-05-13 22 views
6

Giả sử có đã được viết, chương trình máy chủ không thể thay đổi, tiếp nhận như vậy ++ struct C bằng ổ cắm:Làm thế nào để gửi cấu trúc tương thích socket C++ từ Java?

#pragma pack(push, 2) 
struct Data { 
    double x; 
    double y; 
    double z; 
    long frameNumber; 
}; 
#pragma pack(pop) 

nền tảng: C++/32-bit Windows Application biên soạn trong Visual Studio 2008

Làm thế nào để gửi dữ liệu như vậy từ Java Socket? Tôi đã có ý định điền vào ByteBuffer với putDouble() và putLong(), cũng putInt() giả sử dài 32 bit, nhưng tôi không thể tạo ra các giá trị hợp lệ.

Tôi cũng đã tạo và gửi dữ liệu ngẫu nhiên và phân bổ byte cấp cấu trúc có vẻ tốt (tôi có thể ngẫu nhiên chỉ một giá trị, ví dụ X), nhưng tôi không thể tạo giá trị chính xác (đại diện kép khác nhau)? công cụ ngẫu nhiên bằng cách gửi Math.random() * Double.MAX_VALUE;

Tôi có thể sử dụng Bộ đệm giao thức của Google trên một mặt (dữ liệu khách hàng sản xuất) để giải quyết vấn đề này không?

nhớ, tôi không thể thay đổi máy chủ (nhận) bên

tôi biết rằng tôi có thể di chuyển gửi dữ liệu đến C++ và sử dụng JNI, nhưng tôi đang tìm kiếm giải pháp đơn giản hơn.

tôi thấy ít nhất 2 vấn đề có thể ở đây:

  • đại diện đôi ở byte cấp cao (nhưvà 76.543.210 vào phía bên kia)
  • bit đại diện trong một byte (như 00000001 và 1000000 vào phía bên kia)

Những thứ đó trông như thế nào trong Java trong C++?

Trong vài giờ tôi sẽ cung cấp dữ liệu mẫu chính xác cho "byte-hack" (chính xác giá trị Java trước khi gửi và giá trị nhận được gấp đôi trong C++)

Về máy chủ xấu thiết kế trả lời

tôi biết rằng máy chủ được thực hiện và không thể thay đổi đó là phần mềm xấu, nhưng môi trường trong vấn đề này là tiêm một số dữ liệu vào ứng dụng cũ nhỏ ở mức "hobbistic-level"

Biểu diễn Java

Có lẽ điều này sẽ giúp một số bit cấp chuyên gia C++:

Long.toBinaryString(Double.doubleToRawLongBits((double) 0)); 
// 000000000000000000000000000000000000000000000000000000000000000 

Long.toBinaryString(Double.doubleToRawLongBits(1)); 
// 011111111110000000000000000000000000000000000000000000000000000 

Long.toBinaryString(Double.doubleToRawLongBits(1.1)); 
// 011111111110001100110011001100110011001100110011001100110011010 

Long.toBinaryString(Double.doubleToRawLongBits(1024)); 
// 100000010010000000000000000000000000000000000000000000000000000 

Long.toBinaryString(Double.doubleToRawLongBits(1024.1024)); 
// 100000010010000000000000110100011011011100010111010110001110001 

Long.toBinaryString(Double.doubleToRawLongBits(Double.MAX_VALUE)); 
// 111111111101111111111111111111111111111111111111111111111111111 
+0

không phải lo lắng về máy chủ không thể thay đổi. Điều này rất phổ biến xảy ra và thường không đáng để thử và sửa chữa. Trong lập trình sở thích, bạn luôn có thể thay đổi mọi thứ bất cứ khi nào bạn muốn. Tuy nhiên, chuyên nghiệp, tất cả các quy tắc đều thay đổi. – xaxxon

+0

@killer_PL, cách sử dụng JNI để chuyển đổi các loại Java sang các loại VC++? – megabyte1024

+0

@ megabyte1024, ý tưởng hay, tôi sẽ tìm nó trong trường hợp xấu nhất, nhưng bây giờ tôi sẽ đợi một số giải pháp đơn giản hơn –

Trả lời

3

I figured it out. Int giá trị được gửi tốt (propably, không thể kiểm tra này chắc chắn 100% trong chương trình máy chủ), vấn đề là với tăng gấp đôi endian. Bạn cần phải chuyển đổi gấp đôi trước khi gửi:

public static double changeEndian(double x) { 
     ByteBuffer cv = ByteBuffer.allocate(8).putDouble(x); 
     cv.order(ByteOrder.LITTLE_ENDIAN); 
     cv.rewind(); 
     return cv.getDouble(); 
} 

Và sử dụng ByteBufer với putDouble()/putInt().

+0

REALLY này có vẻ sai. float và double tương thích với IEEE 754 không có thứ tự byte thay đổi giữa các nền tảng. http://steve.hollasch.net/cgindex/coding/ieeefloat.html và https://en.wikipedia.org/wiki/Double_precision_floating-point_format không đề cập đến bất kỳ điều gì về các đơn hàng byte. Ngoài ra, trong khi nó không phải là bằng chứng kết luận, api C có htonl và htons, nhưng không có htonf hoặc htond. Java sử dụng các số dấu phẩy động IEEE 754 http://people.uncw.edu/tompkinsj/133/Numbers/Reals.htm. Nó khó tìm hơn, nhưng tôi tin rằng phần cứng x86 chỉ hỗ trợ điểm nổi IEEE 754 nguyên bản – xaxxon

+1

Hrmm .. Tôi đoán định dạng IEEE 754 không chỉ định tính xác thực, để nó mở ra để giải thích. Đã học được điều gì đó ngày hôm nay. – xaxxon

1

Bạn sẽ cần phải xác minh mã hóa được sử dụng để tăng gấp đôi (thường là một tiêu chuẩn IEEE, nhưng nó không phải) cũng dài (lớn vs nhỏ endian) trên nền tảng với máy chủ. Bạn cũng sẽ cần phải xác định bất kỳ padding tham gia là tốt.

Sau đó, bạn sẽ cần phải tạo thủ công các giá trị nhị phân phù hợp để gửi nếu chúng không phải là mã hóa gốc java. Điều này có thể không tầm thường, đặc biệt là đối với các giá trị dấu chấm động, nếu bạn đang ở trên một nền tảng máy chủ khá lộn xộn.

Ngoài ra, theo dõi người quyết định sử dụng một giao thức nhị phân tiềm ẩn cho máy chủ bạn không thể thay đổi và sử dụng cao su vòi giải mã trên chúng:

http://en.wikipedia.org/wiki/Rubber-hose_cryptanalysis

Không có cách nào dễ dàng để làm nó, mà không biết tất cả các chi tiết về nền tảng của máy chủ.

Java có một biểu diễn tiêu chuẩn cho các float và int trên tất cả các nền tảng, nhưng C++ không xác định những thứ đó. Đó là nền tảng/kiến ​​trúc cụ thể cho C++.

+0

Thông tin nền tảng được cập nhật. Đệm là tốt đẹp (0), bởi vì tôi có thể thay đổi các giá trị được chọn ngẫu nhiên, tôi chỉ không thể đại diện cho giá trị gấp đôi chính xác như tôi muốn. –

+0

Tôi không có hệ thống để tìm hiểu điều này. Nghe có vẻ như bạn biết cơ bản phải làm gì và tôi không nghĩ rằng bạn sẽ gặp phải vấn đề về định dạng điểm nổi dựa trên các cửa sổ đang chạy. Hãy chắc chắn không cố gắng để buộc một "mạng byte đặt hàng" của bạn nổi.Trên nền tảng lành mạnh (các cửa sổ thực sự được tính là lành mạnh trong trường hợp này), tất cả đều giống nhau. Nếu bạn nhận được câu trả lời tốt hơn, tôi sẽ xóa câu trả lời này. – xaxxon

3

Giả sử có đã được viết, chương trình máy chủ không thể thay đổi, tiếp nhận như C++ struct bằng ổ cắm

Sau đó, bạn đã có một chính vấn đề mà một số người chưa biết có vui lòng để lại bạn như là một di sản. Bây giờ bạn có để tạo ra mã Java để phù hợp với quan niệm một C cụ thể ++ biên dịch của các định dạng dây của một cụ struct, mà phụ thuộc vào:

  • phần cứng
  • các nhà cung cấp trình biên dịch
  • trình biên dịch phiên bản
  • các tùy chọn biên soạn
  • cáC#pragmas xung quanh
  • ...

I mạnh mẽ khuyên bạn nên tận dụng cơ hội để sửa toàn bộ megillah và xác định định dạng dây thích hợp cho giao dịch.

Một khi bạn đã làm điều đó bạn có thể bắt chước nó dễ dàng đủ với các cơ sở của DataOutputStream, hoặc nếu vấn đề thậm chí còn tồi tệ hơn và endian-Ness là tham gia, nio cộng ByteBuffer.

+0

hoàn toàn có thể họ có nguồn cho chương trình, nhưng có một số khách hàng trong tự nhiên và không thể dễ dàng thay đổi định dạng. Nếu tất cả các khách hàng của họ là các máy khách Windows 32 bit, thì nó có thể không phải là một vấn đề lớn - cho đến bây giờ. Tôi không nói điều này là tốt, nhưng tôi có thể thấy nó có thể xảy ra như thế nào và làm thế nào bạn có thể bị mắc kẹt với nó. – xaxxon

+1

@xaxxon Tôi không nói bất cứ điều gì về * thay đổi * định dạng. Tôi đã nói về * định nghĩa * định dạng, về mặt khác với định nghĩa struct, phụ thuộc vào tất cả những điều tôi đã nói ở trên, và không nghi ngờ gì nữa, tôi quên mất. – EJP

+0

Tôi hiểu. Vâng, điều đó có ý nghĩa. Về cơ bản ghi lại những gì bạn tìm thấy khi bạn đang thực hiện cuộc điều tra này để những người khác không phải làm như vậy. – xaxxon

Các vấn đề liên quan