Forum: PC-Programmierung Daten per C++ an Java-Programm: Java-Typenproblem?


von Nils (Gast)


Lesenswert?

Moin moin,

Ich versuche, per TCP/IP-Verbindung Daten von einem C++-Programm in ein 
Java-Programm zu schaufeln. Übertragen wird ein Array aus Short-Werten, 
die auf meinem System sowohl in C++ als auch in Java zwei Bytes lang 
sind. Es kommen auch Daten an, nur sieht es so aus, als ob Java nur das 
niederwertige Byte auswertet.

Im fogenden Beispiel gibt z.B. die Javakonsole aus: "Data: 0,1,0,-1,-2". 
Wobei die erste Zahl (hier 0) ja vom C++-Programm mit jedem neuen Senden 
inkrementiert wird. Dieser Wert läuft (laut Java-Ausgabe) hoch bis 127, 
dann von -127 wieder in Richtung 0 und so fort. Wie ein überlaufender 
vorzeichenbehafteter 8-bit-Wert. Auf der C++-Seite zählt der Wert ganz 
normal hoch bis 32767, bevor er überläuft.

Ich habe schon probiert, die zwei Bytes auf der Java-Seite zu 
vertauschen (big/little-endian-Problem), dann kommen viel zu große 
Zahlen raus. Im Moment passen wenigsten die positiven und negativen 
Zahlen zwischen -127 und 127, deswegen denke ich, daß das Problem nicht 
mit big/little-endian zu tun hat??

Kann es sein, daß Java schon beim Einlesen der Daten aus dem buffer die 
Daten wegen des Datentyps "byte" anders interpretiert als C++ und dann 
der folgende Cast auf Short nicht mehr funktioniert? Dummerweise gibt es 
keine Funktion, die aus einem InputStream gleich short-Werte, also 
Zwei-Byte-Häppchen ausliest, oder?

Der Code auf der C++-Seite:
1
short senddata[5]={0,-255,-256,-257,-258};
2
3
while(1) {
4
   send(ComSocket,(const char *)&senddata,sizeof(senddata),0);
5
   senddata[0]++;
6
}


Der Code auf der Java-Seite (im Receive-Thread):
1
class DataSet {
2
   DataSet() {
3
      Data=new short[5];
4
   };
5
   public static int tagnr;
6
   public static char valid;
7
   public static short Data[];
8
}
9
10
while(true) {
11
int n=0;
12
try {
13
   if(IStr.available()>0) {
14
      byte buffer[]=new byte[10];
15
      n=IStr.read(buffer,0,10);          
16
      DataSet d=new DataSet();
17
      for(int i=0;i<5;i++)
18
         DataSet.Data[i]=(short)buffer[i*2];
19
System.out.println("Data:"+DataSet.Data[0]+","+DataSet.Data[1]+","+DataSet.Data[2]+","+DataSet.Data[3]+","+DataSet.Data[4]);
20
      }
21
   }
22
   catch(IOException ioe) { };
23
}

Vielen Dank für jede Hilfe,

Nils

von Bobby (Gast)


Lesenswert?

> DataSet.Data[i]=(short)buffer[i*2];

buffer[i*2] ist ein Byte. Das wandelst Du in ein short.
Und das geht schief....


Warum liest Du die Daten nicht gleich richtig ein:

zb so

      n=IStr.read((byte)DataSet.Data,0,10);

Du solltest eventuell auch den Rückgabewert n auswerten.

Gebe allerdings zu, dass ich von Java keinen blassen Schimmer
habe...

von Nils B. (minifriese)


Lesenswert?

Moin,
Danke für den Hinweis.

Ich habe mal den Teil
1
   byte buffer[]=new byte[10];
2
   n=IStr.read(buffer,0,10);          
3
   DataSet d=new DataSet();
4
   for(int i=0;i<5;i++)
5
      DataSet.Data[i]=(short)buffer[i*2];
ersetzt durch
1
   DataSet d=new DataSet();
2
   n=IStr.read((byte[])d.Data,0,10);
Das mag allerdings der Compiler nicht: "Inconvertible types" (ich 
benutze JCreator mit SDK1.5.0_05).

Das dürfte auch der Kern meines Problems sein, denke ich. Ich hätte 
gerne eine Funktion, die das aus dem Stream kommende Array 
(un-interpretiert, so wie die bytes halt kommen) auf mein Short-Array in 
der DataSet-Instanz kopiert. Dort würden dann wieder je zwei Bytes als 
short interpretiert und alles wäre gut.

Aber sowas wie memcpy() gibt es ja in Java nicht, richtig? Ich hatte 
gehofft, daß (short)buffer[i*2] die beiden bytes in buffer[i] und 
buffer[i+1] in einen short packt. War wohl nix.

Gibt's vielleicht noch irgendwelche Klassen, die ich um meinen 
InputStream wickeln kann, damit ich short-Variablen daraus lesen kann? 
BufferedInputStream kann das anscheinend ebenfalls nicht...

Danke,
Nils

von Dirk (Gast)


Lesenswert?

Bei mir musste ich mal Integerwerte aus einem Bytestream lesen.
Dazu habe ich den Bytestream in einen Puffer gelesen und dann daraus 
Integers gemacht.
Hier der Code:
1
// make integer from 4 byte buffer
2
  int makeint(int index) {
3
    return( (byteToInt(buffer[index])) + (byteToInt(buffer[index + 1])) * 256 + (byteToInt(buffer[index + 2])) * 65536 + (byteToInt(buffer[index + 3])) * 16777216);
4
  }
5
6
// convert byte unsigned to integer
7
  static int byteToInt( byte b ) {
8
    return b & 0xff;
9
  }

von Markus V. (Gast)


Lesenswert?

@Nils

Wie wär's denn mit
1
  InputStream IStr = ...
2
  ObjectInputStream OIstr = new ObjectInputStream(IStr);
3
  ...
4
  DataSet.Data[i] = OIStr.readShort();
5
  ...
Ob das allerdings funktioniert, ist nicht unbedingt gesagt, weil 
C++-short und Java-Short nicht notwendigerweise gleich im Speicher 
abgelegt werden (little endian/big endian). In diesme Fall solltest Du 
Dirks Variante in Betracht ziehen.

Es hat übrigens (k)eine Minute gedauert, die Klasse ObjectInputStream im 
Package java.io in der JDK-Dokumentation zu finden. ;o)

Gruß
Markus V.

von Nils B. (minifriese)


Lesenswert?

Moin!
Bin gerade auf Arbeit und kann daher nicht sofort testen. Ich hätte 
jetzt auch Dirks Methode genommen und mir den short-Wert aus den 
einzelnen bytes zusammenaddiert bzw. über Bitoperatoren rausgeholt. Ist 
natürlich umständlich, aber was will man machen ;-)

@Markus: Den ObjectInputStream werde ich natürlich auch ausprobieren, 
das sieht ja genau passend aus für mein Problem.
Was für eine Java-Doku benutzt du denn? Ich habe einfach die zum SDK 
gehörende Doku (ist ein dickes zip-file) entpackt und bekomme dann eine 
Verzeichnisstruktur. Ziemlich weit oben liegt eine "index.html", die 
rufe ich auf. Und bekomme links einen Frame mit allen (!) Klassen und im 
Hauptframe die Eigenschaften, Methoden usw. dieser Klasse. Aber eben 
keine Suchfunktion. Hast du da was besseres? Was vielleicht der MSDN 
ähnelt und Kontextsuche ermöglicht?

Danke und Gruß,
Nils

von Nils B. (minifriese)


Lesenswert?

Nachdem du jetzt das Schlüsselwort geliefert hast: Beim 
ObjectInputStream wird auch ein DataInputStream erwähnt. Der paßt 
vielleicht noch besser, weil die Daten nicht serialisiert vorliegen 
müssen, sondern nur als Bytestream. Naja, ich werde heute abend mal ein 
wenig testen und dann berichten...
Nils

von Markus V. (Gast)


Lesenswert?

@Nils
Schön, daß ich Dich auf die Spur bringen konnte. Wenn ich die Doku von 
DataInputStream und ObjectInputStream lese, dürfte DataInputStream 
wahrscheinlich besser geeignet sein. ;-)

Zum Thema Doku der Class-Library: Ich verwende genau dieses (entpackte) 
ZIP-File und habe in meinem Browser einen schnell zu erreichenden Link 
auf das lokale index.html-File. Allerdings enthält mein Browser-Fenster 
3 (!) Frames. Oben links ist ein Frame mit Links auf die Packages. Whält 
man eines aus, werden unten links nur noch die Interfaces, Classes und 
Exceptions des betreffenden Packages angezeigt. Zu jedem Package gibt es 
dann einen Überblick, zu was es gedacht ist und was darin enthalten ist.

Und wenn man es ganz genau nimmt, ist meine Einstiegsseite nicht die der 
Klassen-Bibilothek sondern eine Übersichtsseite mit Verweisen zur Suche 
(habe ich gerade entdeckt), Links zur Klassen-Doku, Links zu Tutorials, 
die recht gut sind, ...

Insgesamt finde ich die Java-Klassen-Doku übersichtlicher und 
vollständiger als das MSDN-Zeugs.

Für die Suche verwende ich übrigens zumeist Google. Die Ergebnisse sind 
mindestens so hilfreich wie die MSDN-Suche. Eine kontextsensitive Hilfe 
dürftest Du bei Eclipse oder NetBeans finden, beides Freeware und DIE 
IDEs für Java-Entwicklung.

Gruß
Markus V.

von Nils (Gast)


Lesenswert?

So, es hat funktioniert, mit folgendem Code auf der Java-Seite:
1
IStr=Sock.getInputStream();
2
DIStr=new DataInputStream(IStr);
3
4
short big_to_little_endian(short x) {
5
   return (short)(((x>>8)&0xff)+((x << 8)&0xff00));
6
}
7
8
DataSet d=new DataSet();
9
for(int i=0;i<5;i++)
10
   DataSet.Data[i]=big_to_little_endian(DIStr.readShort());
Danke an alle Beteiligten! ;-)

Nils

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.