# Kommunikation auf Byte-Ebene zw. C und Java via Socket



## tuxedo (28. Okt 2005)

Hallo,

ich muss einen Treiberwrapper fuer eine Interfacekarte schreiben der den C-Treiber auf Java adaptiert.
Fuer die initiellen Einstellungen verwende ich JNI. Fuer die Rohdaten will ich Sockets einsetzen und das ganze somit evtl sogar noch netzwerkfaehig machen.

Sockets habe ich deshalb gewaehlt weil hier direkt und ohne Umwege kommuniziert wird. Beim Transfer kommt es auf sehr exaktes Timing und Geschwindigkeit an. Da gehen schon Megabyteweise Daten durch.

auf der C Seite kommen beim Treiber Messages an die aus mehreren Informationen bestehen die in einzelnen Variablen verpackt sind. IDs, Roh-Daten und noch ein paar Parameter.

Sagen wir eine Message besteht aus 2 Ints, 1 String und einem Byte-Array. Dies Daten muessen auf der C-Seite in den Socket rein und auf der Java-Seite aus einem Bytestream oder sowas wieder raus. 

Auf beiden Seiten laufen je 2 Threads die die Daten entgegennehmen und weiterschicken. Also ein Thread fuer TX und einer fuer RX.

Kann mir jemand Tipps geben wie man aus einem Byte-Stream ind Java wieder die Informationen rausliest ? Also z.B. nacheinander wieder 2 Ints, 1 String und ein Byte-Array macht wenn auf der senden Seite ein C-Programm steht das die Daten bei sich in den socket reinfuettert?

Ein Tipp wo man sowas nachlesen kann wueder mir ja auch schon reichen.

Gruss
Alex


----------



## Nick H. (29. Okt 2005)

da biste wihl mit DataStreams am besten beraten
kannste einfach mal in der Doku nachschauen
mit denen kann man ganz einfach Integer, Strings usw. ein und auslesen


----------



## tuxedo (7. Nov 2005)

So, bin aum Urlaub zurueck.

Hab mir eben die DataStreams angeschaut. Sieht vielversprechend aus. 
Jetzt muss ich nur noch rausfinden/testen wie das aussieht wenn der Input-Stream auf Java-Seite mit Variablen von der C-Seite aus gefuettert wird.

Gruss
Alex


----------



## Beni (7. Nov 2005)

Hm, bei den DataStreams kann es Probleme bezüglich little/big-endian geben.

Sofern es nicht geht, guck dir den Code der DataStreams mal an. Da steht drin, wie man aus mehreren Bytes irgendwas neues erzeugt. Damit kannst du was eigenes basteln.


----------



## Nick H. (7. Nov 2005)

was meinst du denn mit little/big-endian?
das hab ich noch nie gehört


----------



## tuxedo (7. Nov 2005)

Nick H. hat gesagt.:
			
		

> was meinst du denn mit little/big-endian?
> das hab ich noch nie gehört



Nicht verzagen, Wikipedia.de fragen:

http://de.wikipedia.org/wiki/Spezial:Search?search=big+endian

Gruss
Alex


----------



## tuxedo (10. Nov 2005)

So, habe die letzte Zeit jede Menge herumexperimentiert. Aber ich schaffs nicht einen in C in den Socket reingeschobenes Byte auf Java Seite wieder erfolgreich zu lesen, geschweige denn einzelne Typen auszulesen wie int, string, char, byte etc...

Weiss jemand wo ich Beispielcode fuer mein Problem finde? Habe vermehrt im Netz gelesen dass sowas schon gemacht wurde, doch keiner gibt Auskunft darueber wie...

- Alex


----------



## Mag1c (10. Nov 2005)

Hi,

zeig doch mal ein bisschen Code.

Gruß
Mag1c


----------



## tuxedo (14. Nov 2005)

So, ich bin jetzt ein Stueck weiter... Ich habs geschafft einfache Integer via Socket von C nach Java zu schicken. Um das ganze eleganter zu loesen will ich auf Java-Seite nur mit Objecten arbeiten und habe vor die serialisierung manuel vor zu nehmen.

Beispiel:

Die Klasse die die zu sendenden Daten enthalten soll

```
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Message implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public int var1;
	
	private void writeObject( ObjectOutputStream oos ) throws IOException
	  {
		System.out.println("Schreibe var1");
		oos.writeInt(var1);
	  }

	 
	  private void readObject( ObjectInputStream ois ) throws IOException
	  {
		  System.out.println("Lese var1");
		  var1=ois.readInt();
	  }
}
```


Kleiner Test-Server der Verbindungen entgegen nimmt, eine Int Zahl einliest, diese in das Message-Object steckt und die Message wieder zurueck-serialisiert in die Leitung steckt...

```
import java.net.*;
import java.io.*;

public class Server
{
	public static void main( String args[] ) throws ClassNotFoundException {
		ServerSocket server;
		Socket client = null;
		try {
			server = new ServerSocket( 2000 );


			while ( true ) {
				System.out.println("Warte auf Clientverbindung...");
				client = server.accept();
				System.out.println("Client "+client.getInetAddress().getHostAddress()+" hat sich mit uns verbunden...");
				
				System.out.println("Erzeuge Streams...");
				
				
				
				InputStream  is  = client.getInputStream();
					System.out.println("\tInputStream erzeugt");
				OutputStream os = client.getOutputStream();
					System.out.println("\tOutputStream erzeugt");
				
				ObjectOutputStream out = new ObjectOutputStream(os);
					System.out.println("\tObjectOutputStream Stream erzeugt");
				ObjectInputStream in = new ObjectInputStream(is);
					System.out.println("\tObjectInputStream Stream erzeugt");
				
					
					
				Message m = new Message();
				m.var1=0;
				
				int start=-1;
				while (true){
					try {      
						System.out.print("Lese Message...");
						
						Object o = in.readObject();
						if (o==null) break;
						m = (Message) o;
						
						System.out.println("Gelesen: '"+m.var1+"'");
						
						System.out.print("Schreibe Message...");
						out.writeObject(m);
						System.out.println("fertig...");
						
					} catch (IOException e) {
						e.printStackTrace();
						System.exit(0);
					} 
					
					
				}
			}
		} 
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			client.close();
		} 
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
```


Kleiner C-Test-Client der den Int "msg" versendet und auf die Antwort wartet...

```
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <winsock.h>

#define BUF_SIZ	4096

void cut(char *s)
{
	while (*s && (*s != '\r') && (*s != '\n'))
		s++;
	*s = '\0';
}


int main(int argc, char *argv[])
{
	struct sockaddr_in addr;
	struct hostent *host;
	int s;
	int i=0;
	int msg=321;
	int rcvlen;
	char buf[1024];
	WSADATA	wsa;

	if (argc != 3)
	{
		fprintf(stderr, "usage: %s <Host> <Port>\n", argv[0]);
		return 1;
	}

	if (WSAStartup(MAKEWORD(1, 1), &wsa))
	{
		fprintf(stderr, "WSAStartup() failed: %lu\n", WSAGetLastError());
		return 2;
	}

	if ((addr.sin_addr.s_addr = inet_addr(argv[1])) == -1)
	{
		host = gethostbyname(argv[1]);
		if (!host)
		{
			fprintf(stderr, "gethostbyname() failed: %lu\n", WSAGetLastError());
			return 3;
		}
		addr.sin_addr = *(struct in_addr*)host->h_addr;
	}

	if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1)
	{
		fprintf(stderr, "socket() failed: %lu\n", WSAGetLastError());
		return 4;
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons(atol(argv[2]));

	printf("connecting to %s\n", inet_ntoa(addr.sin_addr));
	if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) == -1)
	{
		fprintf(stderr, "connect() failed: %lu", WSAGetLastError());
		return 5;
	}

	
	
	if (send (s, &msg, 1, 0) == -1) {
		perror ("Fehler beim senden send()");
	}


	rcvlen=recv (s, buf, 1024, 0);

	printf("rx length: %i\n",rcvlen);

	for (i=0;i<rcvlen;i++){
		printf("%u ",buf[i]);
	}
 



	Sleep(5000);
	closesocket(s);

	return 0;
}
```

Doch irgendwie schafft es Java nicht den ObjectInputStream zu erzeugen:



> Warte auf Clientverbindung...
> Client 127.0.0.1 hat sich mit uns verbunden...
> Erzeuge Streams...
> InputStream erzeugt
> ...



Any ideas why ?

gruss
Alex


----------



## tuxedo (14. Nov 2005)

Antwort gefunden...

Beim erstellen eines ObjectOutputStreams sendet Java auf Byte-Ebene irgendwelchen Infos ueber den Socket. Auf der anderen Seite auf der ein ObjectInputStream erzeugt wird wird auf diese Information gewartet.

Ich habe nun jetzt versucht einen ObjectInputStream auf Java-Seite zu erzeugen. Java wartet nun auf Infos von der anderen Seite bzgl des ObjectInputStreams, erwartet also einen ObjectOutputStream... 

In C habe ich sowas allerdings nicht und Java bricht irgendwann beim Stream erzeugen ab da die falschen (oder keine) Informationen ankommen.

Werde es jetzt so loesen:

Eine Message-Klasse die writeData und readData kennt und mit denen ich meine Informationen aehnlich dem eigenen serialisieren mittels writeInt/Char/String/Byte sende und empfange.

Denke das sollte gehen.

Gruss
Alex


----------



## tuxedo (14. Nov 2005)

Jupp, das geht. Wenn man dann noch weiss dass Java die Integer in einer anderen Bytereihenfolge benutzt klappt das auch ganz gut 

- Alex


----------



## Gast (4. Jan 2006)

Das ist die nur bei Java so, sondern das sind verallgemeinerte konventionen !


----------



## tuxedo (5. Jan 2006)

Bringt mir nur nix wenn es eine Konvention ist und C und Java sich nicht BEIDE dran halten. Es funktioniert jedenfalls 

- Alex


----------

