# UDP und Objekte



## Lord_Aratorn (19. Juni 2008)

Hallo erstmal, da ich hier im Forum schon öfters nützliche dinge gefunden habe, doch nun nicht mehr weiter weiß, habe ich mir mal nen Account erstellt und hier mal direkt zu fragen.

Also es geht darum, dass ich über das netzwerk UDP-Packete empfangen und verschicken will.
Hierfür benutze ich DatagrammPacket/DatagrammSocket.

```
DatagramSocket ds = new DatagramSocket(2902);
byte[] array = new byte[1024]
		DatagramPacket dp = new DatagramPacket(array, array.length);
		ds.receive(dp);
```
nun habe ich die Daten des Udp-packets in meinem array.

Die Sache ist, wie erstelle ich aus dem erhaltenen byte[] wieder ein brauchbares Objekt?

z.b.
class testObjekt implements Serializable{
int nummer;
String Name;
String Adresse;
}


P.S. das System von dem ich die Packete empfange, kenne ich nicht, ich kennen nur die Datenstruktur, die übermittelt wird.


----------



## zerix (19. Juni 2008)

Hallo,

wenn es sich um ein Java-Object handelt, kann man das mit dem ObjectInputStream und dem ByteArrayInputStream zusammen.

MFG

Sascha


----------



## Lord_Aratorn (19. Juni 2008)

hey könntest du mir dazu Code liefern?
btw. das Objekt ist eine struct, also c/c++ darum auch mein Problem.
Ich habe nun schon eine Fuktion geschrieben, die aus einem byte[] ein objekt des Typs generiert was ich weiterverwenden möchte. Doch dachte ich mir, dass es nicht normal sein kann, das man immer von byte[] in was weiß ich konvertieren muss. ich könnte mir vorstellen das dieses richtig ätzend ist, wenn man ein richtig großes Objekt benutzt. Da man ja quasi doppelten speicher benötigt.


----------



## zerix (19. Juni 2008)

Hey,

nächstes mal bitte in der API nachschauen.
Mir wurde auch mal gesagt, dass google auch helfen soll.
Selbst zu deiner erste Frage findet man eine Menge. Hättest nur mal nach "Object byte[]" suchen müssen.


```
byte[] b = new byte[12];
ByteArrayInputStream bais = new ByteArrayInputStream(b);
ObjectInputStream ois = new ObjectInputStream(bais);
```

MFG

Sascha


----------



## Lord_Aratorn (19. Juni 2008)

ja, das war ja schon klar. Doch wie mache ich das bei den udp packeten?


----------



## Thomas Darimont (19. Juni 2008)

Hallo,

wenn du serialisierte Objekte per UDP versenden möchtest, musst du einige Dinge beachten. Im Gegensatz zu TCP bietet UDP keine garantierte 
Übertragung auf Protokollebene, genausowenig wird die Empfangsreihenfolge bei mehreren logisch zusammengehörigen Paketen nicht garantiert.
D.h. du musst hier zusätzliche Logik hinterlegen, die Pakete in der "richtigen" Reihenfolge wieder zusammensetzen kann und bei verlust eines
Paketes eine Neueübertragung triggert. Das ist insbesonders dann interessant, wenn deine Objekte nicht in ein UDP Paket passen und diese deshalb 
auf mehrere Pakete verteilen musst.

Schau mal hier:
http://www.tutorials.de/forum/java/241551-netzwerk-udp-multicast-socket-pakete-empfangen.html
http://www.tutorials.de/forum/java/205651-udp-mit-java.html

Gruß Tom


----------



## _jsd_ (20. Juni 2008)

Hi,

wenn es nicht unbedingt per UDP sein muß ( kna was Du vorhast), könnte RMI/CORBA/SOAP für Dich interresant sein...

hmf


----------



## Lord_Aratorn (21. Juni 2008)

Erstmal danke Tom, doch hillft das mir in keiner weise Weiter, da mein eigentliches Problem falsch verstanden wurde. 

Also mein Problem liegt darin. Ich habe einen Client, der auf C basiert und mir UDP-Packete ins Netz wirft.
Ich möchte nun unter Java einen Client programmieren, der diese Packete empfängt, den Inhalt auswertet, und aufgrund des Inhalts eine Antwortnachricht erstellt, die er dann wieder rausschickt.
Es werden vom Client nur korrekte UDP-Packtete angenommen (mit Header und Checksum)

Das schicken und empfangen ist nicht das Problem, da ich dafür das DatagrammPacket benutze, und die vordefinierten Methoden (send, recive). Die ein UDP-Packet, in ein angeggebenes Netz schicken oder aus jenem empfangen.

Nun kommt es aber. Die empfangenen Packete sind von den internen Datenstrukturen so komplex, das ich mir für den leichteren Umgang Objekte erstellen möchte, die das Packet darstellen.
Ein Packet sieht abstrakt beispielhaft so aus:

packet{
int;
int;
char[64];
float;
long;
int;​}tekcap

Ich habe mir nun ein Java Objekt erstellt Beispiel:

public class Packet{
int nummer;
int geburtsjahr;
String name;
float kontostand;
long nenlong;
int Kennzeichennummer;​}

Quasi möchte ich den erhaltenen Datenstrom (byte[]) zu einem solchen Objekt transformieren, und wieder ein Objekt in byte[] da ich es 1) wieder verschicken muss und 2) ich nur ein byte[9 verschicken kann.


ich denke, das es nur verständlich ist. sorry



@JSD ja ich kenne die vorgeschlagenen Bibliotheken/Frameworks alle, doch kann ich sie nicht benutzen, da ich mit der gegenstelle kommunizieren will, die auf C basiert.


----------



## Thomas Darimont (21. Juni 2008)

Hallo,

wenn du so mit einem C-Programm interagieren willst, kannst du nicht die normale java Serialisierung verwenden. Statt dessen musst du dich selbst im die binäre Repräsentation deiner Daten kümmern. Das geht am besten mit einem DataOuputStream/DataInputStream oder einem ByteBuffer. Hier musst du dann u.a. auf Byte Order und unterschiedliche Typ-Ausprägungen achten (chars sind in java 2 byte lang, in c nur 1 byte).

schau mal hier:

```
/**
 * 
 */
package de.tutorials.networking;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;

/**
 * @author Tom
 * 
 */
public class UPDPacketExample {

	static class Data {
		int number;
		int yearOfBirth;
		String name;
		float accountBalance;
		long value;
		int licenceIdentifier;

		public int getNumber() {
			return number;
		}

		public void setNumber(int number) {
			this.number = number;
		}

		public int getYearOfBirth() {
			return yearOfBirth;
		}

		public void setYearOfBirth(int yearOfBirth) {
			this.yearOfBirth = yearOfBirth;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public float getAccountBalance() {
			return accountBalance;
		}

		public void setAccountBalance(float accountBalance) {
			this.accountBalance = accountBalance;
		}

		public long getValue() {
			return value;
		}

		public void setValue(long value) {
			this.value = value;
		}

		public int getLicenceIdentifier() {
			return licenceIdentifier;
		}

		public void setLicenceIdentifier(int licenceIdentifier) {
			this.licenceIdentifier = licenceIdentifier;
		}

		@Override
		public String toString() {

			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.append(number);
			stringBuilder.append(" ");
			stringBuilder.append(yearOfBirth);
			stringBuilder.append(" ");
			stringBuilder.append(name);
			stringBuilder.append(" ");
			stringBuilder.append(accountBalance);
			stringBuilder.append(" ");
			stringBuilder.append(value);
			stringBuilder.append(" ");
			stringBuilder.append(licenceIdentifier);

			return stringBuilder.toString();
		}

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) throws IOException {
		Data data = new Data();
		data.setNumber(4711);
		data.setYearOfBirth(1986);
		data.setName("Bubu");
		data.setAccountBalance(10.000F);
		data.setValue(338L);
		data.setLicenceIdentifier(9993);

		System.out.println(data);

		byte[] bytes = serialize(data);
		System.out.println(Arrays.toString(bytes));
		Data clone = deserialize(bytes);
		System.out.println(clone);

	}

	private static Data deserialize(byte[] bytes) throws IOException {

		Data data = new Data();

		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
				bytes);
		DataInputStream dataInputStream = new DataInputStream(
				byteArrayInputStream);

		data.setNumber(dataInputStream.readInt());
		data.setYearOfBirth(dataInputStream.readInt());
		
		byte[] nameBytes = new byte[64];
		dataInputStream.read(nameBytes);
		
		int nonNullCharCount = 0;
		char[] buffer = new char[64];
		for(int i = 0; i < nameBytes.length;i++){
			byte b = nameBytes[i];
			if(b != 0){
				nonNullCharCount++;
			}
			buffer[i] = (char)b;
		}
		
		data.setName(String.valueOf(buffer, 0, nonNullCharCount));
		
		data.setAccountBalance(dataInputStream.readFloat());
		data.setValue(dataInputStream.readLong());
		data.setLicenceIdentifier(dataInputStream.readInt());

		dataInputStream.close();

		return data;
	}

	private static byte[] serialize(Data data) throws IOException {

		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		DataOutputStream dataOutputStream = new DataOutputStream(
				byteArrayOutputStream);

		/*
		 * int; 
		 * int; 
		 * char[64]; 
		 * float; 
		 * long; 
		 * int;
		 */

		dataOutputStream.writeInt(data.getNumber());
		dataOutputStream.writeInt(data.getYearOfBirth());
		byte[] bytes = new byte[64];
		char[] chars = data.getName().toCharArray();
		for (int i = 0; i < Math.min(chars.length,bytes.length); i++) {
			bytes[i] = (byte)chars[i];
		}
		dataOutputStream.write(bytes);
		dataOutputStream.writeFloat(data.getAccountBalance());
		dataOutputStream.writeLong(data.getValue());
		dataOutputStream.writeInt(data.getLicenceIdentifier());

		dataOutputStream.close();

		return byteArrayOutputStream.toByteArray();
	}

}
```

Gruß Tom


----------



## Lord_Aratorn (21. Juni 2008)

sowas hatte ich befürchted
Problem an der Geschichte ist, dass man doppelte Speicherkapatzität braucht. Einmal für das Objekt, und einmal für das byte[]


----------



## Lord_Aratorn (23. Juni 2008)

Ok danke erstmal, aber da habe ich noch eine wirklich wichtige Frage.

Ich serialisiere nun, wie Tom es bereits aufgezeigt hat.



```
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] byte = new byte[18];
byte = "Super sache wieder laenger als 18 Zeichen und dabei wollte ich doch nur 18 zeichen verschicken".getBytes();
DataOutputStream dataOutputStream = new DataOutputStream(
byteArrayOutputStream);
dataOutputStream.write(byte);
```

ich weiß nicht wie ich es formulieren soll. Ich möchte das nicht mehr und nicht weniger als 18 byte verschickt werden. Da Anfang und ende der bytes in dem Stream wichtig sind.

doch wenn ich es wie oben mache, verschickt er den kompletten String

Ich hoffe es war verständlich


----------

