Java Enumeration über Socket übertrag

matzedonier

Cadet 1st Year
Registriert
Feb. 2011
Beiträge
8
Hallo Leute,

ich probiere mich gerade ein bisschen an Socketprogrammierung.
Leider habe ich ein problem mit dem java.io.InputStream bzw. OutputStream.

Ich habe früher c++ programmiert und da gabs eine wunderbare Funktion names sizeof(), diese gibts wohl so einfach nicht in Java, jetzt habe ich die Frage wie ich eigentlich herausfinde wie viel bytes ich schreiben muss bzw lesen muss.

Code-Snippet-Server:
Code:
	private void listen() throws IOException{
		
		while(true){

			..
			NetworkServerClientHandlerEnumeration action = NetworkServerClientHandlerEnumeration.ACTIONLESS;
			..
			if( inputStream.read(action, 0,[B]?????????[/B] == [B]??sizeof(action)??[/B])
			switch(action){
				case HOSTNAME:
					//Hostname lesen ..
					break;
					
				case CHATSEND:
					//Chatsend lesen .. 
					break;
					
			}
			else
			System.out.println("Conversation Error occured!.. Reset connection");
			
		}
 
Musst du nicht schon beim Lesen die Anzahl der zu lesenden Bytes uebergeben?

Alternativ kannst du auch ganze Objekte senden und nicht nur den Enum Wert. Dazu gibt es einen ObjectInputStream.

Als weitere Alternative: Falls du einen Enum Wert uebertragen willst, dann handelt es sich um einen Integerwert. Da muesste es irgendwo sowas wie readInt(...) geben.
 
ah ok, ist enum als in java immer ein "integer", ja die heist dann einfach read.


Und zu deiner frage: Ja ich muss die Länge übergeben wieviel er lesen soll, aber er gibt mir auch die länge zurück, die er wirklich gelesen hat, einfach als zusätzliche Fehlerbehandlung.

Ich werde es gleich mal mit dem ObjectStream testen.
 
Aber sparsam mit dem ObjectStream umgehen, und vorallem bewusst! Sehr ressourcenfressend das Teil.
 
Also Read() gibt zurück, wieviele Bytes in dem übergegeben Buffer mit Daten gefüllt sind.
Den Buffer musst du natürlich anlegen und übergeben. Idealerweise müssen das hier 8 Byte sein, weil ein enum-Eintrag=Int32=32Bit=8 Byte.

Den Buffer musst du dann dementsprechend auslesen und zum enum konvertieren.

Sollte der Buffer bei einer anderen Verwendungsweise zu klein sein, werden die Daten in buffer-breite Happen geteilt und Read wird entsprechend mehrmals aufgerufen durch die Schleife.

Da je nach Protokolleinstellungen soweit ich weiß die Pakete auch gerne mal zusammengeschustert werden, kann es sein, dass bei einem größeren Buffer dieser erstmal gefüllt wird, solange die Pakete zeitlich nicht zu groß auseinanderliegen. Ich glaube das nennt sich "Nagle-Algorithmus" oder so. (Spekulation)
Naja, wie auch immer, mit der Vorgehensweise in den ersten zwei Absätzen sollte es gehen.
 
derlolomat schrieb:
Idealerweise müssen das hier 8 Byte sein, weil ein enum-Eintrag=Int32=32Bit=8 Byte.
32Bit wären aber 4 Byte

derlolomat schrieb:
Sollte der Buffer bei einer anderen Verwendungsweise zu klein sein, werden die Daten in buffer-breite Happen geteilt und Read wird entsprechend mehrmals aufgerufen durch die Schleife.
jup, aber auch beachten, dass man immer in einer Schleife lesen muss, denn nur weil der Buffer x Byte groß ist wird er nicht bei jeder Leseoperation soweit gefüllt, sondern nur soweit wie gerade Daten da sind, das wird sehr gerne vergessen.

derlolomat schrieb:
IDa je nach Protokolleinstellungen soweit ich weiß die Pakete auch gerne mal zusammengeschustert werden, kann es sein, dass bei einem größeren Buffer dieser erstmal gefüllt wird, solange die Pakete zeitlich nicht zu groß auseinanderliegen. Ich glaube das nennt sich "Nagle-Algorithmus" oder so. (Spekulation)
korrekt der Nagle-Algorithmus ist eine TCP-Optimierung um das Senden mehrere kleiner Pakete zu vermeiden, wenn Daten schnell hintereinander auf den Stream geschrieben werden, sollten diese nur wenige Millisekunden auseinander liegen können diese zusammen gesendet werden.



statt mit Gewurschtel anzufangen, dass ein int 4 Byte groß ist würde ich dir empfehlen lieber direkt ein eigenes kleines binäres Protokoll zu definieren mit der Paketgröße als ersten festen Datenblock, das macht es später viel einfacher alles anzupassen.
 
ice-breaker schrieb:
32Bit wären aber 4 Byte

Hmm, die 23Uhr fühlten sich wohl etwas später für mich an.

ice-breaker schrieb:
jup, aber auch beachten, dass man immer in einer Schleife lesen muss, denn nur weil der Buffer x Byte groß ist wird er nicht bei jeder Leseoperation soweit gefüllt, sondern nur soweit wie gerade Daten da sind, das wird sehr gerne vergessen.

Vermutung:
Irrelevant bei dem Aufgabenkontext, weil dieses Phänomen nicht auftritt, wenn Bufferlänge<=Paketlänge?
 
derlolomat schrieb:
Vermutung:
Irrelevant bei dem Aufgabenkontext, weil dieses Phänomen nicht auftritt, wenn Bufferlänge<=Paketlänge?

Nein, du kannst dich da nicht drauf verlassen, niemals.
Denn es könnten ja theoretisch die 4 Byte des Integers auch alle in einzelnen Bytes in den Puffer gelesen werden, das ist zwar sehr unrealistisch, könnte aber passieren.
Niemals auf irgendwelche Annahmen verlassen.
 
derlolomat schrieb:
Idealerweise müssen das hier 8 Byte sein, weil ein enum-Eintrag=Int32=32Bit=8 Byte.

32 Bit sind nicht 8, sondern 4 Byte!

matzedonier schrieb:
ah ok, ist enum als in java immer ein "integer", ja die heist dann einfach read.

Nein, ein Enum ist in Java kein Integer, wie das beispielsweise bei C++ der Fall ist, wo es eine implizite Konvertierung von enum zu int gibt. Es handelt sich dabei um ein Objekt. Es ist aber möglich einen Enum direkt zu instanzieren, mit einem Integer.

PHP:
public enum MyType
{
    ERROR             (0);

    MyType(int type)
    {
        this.type = type;
    }

Über eine Methode lässt sich der Wert von ERROR als Integer dann auslesen.

derlolomat schrieb:
Ich glaube das nennt sich "Nagle-Algorithmus" oder so. (Spekulation)

Richtig. Siehe dazu:

TCP ist ein Stream (dt. Strom) und sollte auch als kontinuierlicher Datenstrom behandelt werden. Versuchen Sie nicht bei einem NetworkStream die Methode Flush aufzurufen, diese Methode hat keine Wirkung auf einen ungepufferten Netzwerkstrom. Der TCP/IP-Stack im Betriebssystem entscheidet wann und wie Pakete gesendet werden. Grundlage bildet der sogenannte Nagle-Algorithmus. Mit dem Nagle-Algorithmus wird das Versenden von vielen kleinen TCP-Datenpaketen über IP-Netze verhindert. Zu diesem Zweck werden beim Nagle-Mechanismus die kleinen Datenpakete zuerst zwischengespeichert und zu einem größeren Datenpaket zusammen gefasst. Mit dieser Technik soll das Netz von unnötig vielen kleinen Datenpaketen entlastet werden. In Verbindung mit dem Nagle-Algorithmus greift noch ein zweiter Algorithmus, der die Größe des Übertragungsfensters bei der TCP-Verbindung steuert. In der Regel versendet der TCP/IP-Stack ein Segment aus dem TCP-Buffer umgehend nach Ihrem Send-Befehl, doch dafür gibt es weder eine Garantie, noch können oder sollten Sie dieses Verhalten auf der Ebene erzwingen. Unter Windows bewirkt der Nagle-Algorithmus eine Zwischenspeicherung der Pakete am Socket für bis zu 200 Millisekunden. Es ist in .NET möglich die Winsock Option TCP_NODELAY zu setzen und damit den Nagle-Algorithmus zu deaktivieren. Dies wird mit der Eigenschaft Socket.NoDelay erreicht.

http://www.codeplanet.eu/tutorials/csharp/4-tcp-ip-socket-programmierung-in-csharp.html?start=1
 
Zuletzt bearbeitet:
Stefan_Sch schrieb:
32 Bit sind nicht 8, sondern 4 Byte!

Manchmal habe ich das Gefühl, dass gewisse Leute mit Ahnung hier nur posten, um alles Mögliche zu kritisieren damit sie sich profilieren können. Das wurde nämlich schon von jemand anderem korrigiert und von mir kommentiert. So wird dem Threadersteller nur leider nicht geholfen, und erst recht nicht wenn dieser sich nicht mehr zu Wort meldet.
 
derlolomat schrieb:
Manchmal habe ich das Gefühl, dass gewisse Leute mit Ahnung hier nur posten, um alles Mögliche zu kritisieren damit sie sich profilieren können. Das wurde nämlich schon von jemand anderem korrigiert und von mir kommentiert. So wird dem Threadersteller nur leider nicht geholfen, und erst recht nicht wenn dieser sich nicht mehr zu Wort meldet.

Beruhige dich. Zum einen hatte ich den Strang nur überflogen und die nachträgliche Berichtigung überlesen, zum anderen habe ich dem Threadersteller explizit bei seinem Problem geholfen.

Die erste Antwort in diesem Thread war nämlich falsch, ein Enum ist in Java kein Integer.

Falls du einen Enum Wert uebertragen willst, dann handelt es sich um einen Integerwert.

Die folgende Aussage ist daher auch zweifach falsch.

Idealerweise müssen das hier 8 Byte sein, weil ein enum-Eintrag=Int32=32Bit=8 Byte.

Ob sich der Threadersteller noch meldet oder nicht, ist mir völlig egal!
 
Tut mir leid an alle die mir bis jetzt geholfen haben,

ich lag die ganze Woche krank und mit Kopfweh im Bett,

deshalb bin ich leider nicht zum coden gekommen.

Ich bin gerade erst am testen und werde morgen berichten wie es mir bisher ergangen ist.

PS: Aber ehrlich gesagte habe ich immern noch keinen richtigen Ansatz.
Ich meine, Integer kann über einfach so übertragen:
OutputStream outputStream;
outputStream.write(b)
Aber Wie ich jetzt ein Enum oder ein anderes Objekt wie ein String übertragen soll weiß ich noch nicht so richtig.

Mein Problem ist immer noch das Sizeof, weil ich ja einfach der write Methode vom OutputStream die größe in byte mitgeben muss.
 
Zuletzt bearbeitet:
matzedonier schrieb:
PS: Aber ehrlich gesagte habe ich immern noch keinen richtigen Ansatz.
Ich meine, Integer kann über einfach so übertragen:

Aber Wie ich jetzt ein Enum oder ein anderes Objekt wie ein String übertragen soll weiß ich noch nicht so richtig.

Mein Problem ist immer noch das Sizeof, weil ich ja einfach der write Methode vom OutputStream die größe in byte mitgeben muss.

Du musst die anderen Beiträge schon lesen!

Mit ObjectStream wird nichts geschrieben, die Klasse ist abstrakt. Sizeof ist auch egal, weil du mit writeInt bereits die Länge festlegst, nämlich ein Int, also 4-Byte.

Ein funktionierendes Beispiel kann wie folgt aussehen.

PHP:
import java.net.*;
import java.io.*;

public class Server
{
    /**
     * @param args the command line arguments
     */
    public static void main(String args[])
    {
        ServerSocket serverSock = null;

        try {
            serverSock = new ServerSocket(5444);
            System.out.println("Server listening on 5444...");
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
        
        while (true) {
            try {
                Socket sock = serverSock.accept();
                InputStream is = sock.getInputStream();
                DataInputStream dis = new DataInputStream(is);
                System.out.println("Nachricht vom Client: " + dis.readInt());
                sock.close();
                dis.close();
            } catch (IOException e) {
                System.err.println(e.getMessage());
            }
        }
    }
}

PHP:
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

class Client
{
    /**
     * @param args the command line arguments
     */
    public static void main(String args[])
    {
        String server = "localhost";
        int port = 5444;
        int value = MyTypes.ERROR.toInt();   // Konvertierung von enum nach int

        try {
            Socket s = new Socket(server, port);
            OutputStream os = s.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);
            dos.writeInt(value);
            s.close();
            dos.close();
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }
}

PHP:
public enum MyTypes
{
    ERROR(0),
    SUCCESS(1);

    MyTypes(int t)
    {
        this.type = t;
    }

    int toInt()
    {
        return type;
    }

    private final int type;
}

Wie ich schon sagte ist ein Enum ein Objekt, kein Integer. Deshalb kann man natürlich über java.io.Serializable auch das gesamte Objekt serialisieren. Mehr zu dazu auf http://www.vineetmanohar.com/2010/01/3-ways-to-serialize-java-enums/ .
 
Zuletzt bearbeitet:
Man könnte jetzt sogar klugscheissen (mach ich besonders gern) und sagen, daß ihr ALLE falsch liegt ... oder zumindest nur bedingt Recht habt. :D So weit ich weiß gab oder gibt es auch einige exotische Plattformen, auf denen ein Byte eben nicht 8 sondern z.B. 7 Bit hat. ;)
 
Schon doof wenn man mit dem Klugscheißen auch noch falsch liegt :p
Auf welcher Platform Java läuft ist egal, die VM stellt Garantien: 1 Byte = 8 Bit, Integer = 4 Byte
 
ice-breaker schrieb:
Schon doof wenn man mit dem Klugscheißen auch noch falsch liegt :p
Auf welcher Platform Java läuft ist egal, die VM stellt Garantien: 1 Byte = 8 Bit, Integer = 4 Byte


Ging's hier nicht um ein Programm, das über das Netz kommuniziert? Da sollte man vielleicht keine Annahmen darüber machen, welche Art von Platform sich auf der anderen Seite befindet, oder? ;) Wer sagt denn, daß die Gegenseite auch in Java geschrieben sein muß? Wenn man prozessübergreifend Daten ausstauscht, sollte man sich auf ein standardisiertes Protokoll stützen, z.b. XDR (External Data Representation) oder etwas in der Art. Muß man natürlich nicht, ist aber sicher robuster.
 
Zuletzt bearbeitet:
Zurück
Oben