Variable übergeben

  • Hallo,
    ich möchte gern wissen wie ich die Variable n an meinen client übergeben kann.
    ich habe einen Server der alle 2 Sekunden einen neuen Integerwert erzeugt.
    Dieser Wert soll an den Client über eine Socketverbindung gesendet werden, nur wie?


    Hier mal mein Code:


    Was zur Zeit passiert iost, wenn ich die Anwendung starte die Ausgabe, "Server gestartet!" und "0" bekomme.
    Die variable n wird alle 2 Sekunden mit dem Wert 1,2,3,4,5,1,2... usw. belegt.
    Dieser Wert soll alle an den Client gesendet werden.


    Gruß
    Brausebernd

  • Hallo,

    Wird das System.out.println("Nachricht vom Client: " + nachricht); Ausgeben?

    ja es wir ausgegeben. sobald der Client eine Verbindung aufbaut.


    kommt beim Client was an?

    Ja da kommt was an und zwar die Zahl wo sich das Programm grad "befindet".
    Danach ist aber "Ruhe" es soll aber alle 2 Sekunden der neue Wert ausgegeben werden.


    Hier mal der Client Code:


    Müsste ich den Handler alle 2 Sekunden "refreshen"?
    oder bin ich da auf dem falschen Weg?


    Gruß
    Brausebernd

  • Müsste ich den Handler alle 2 Sekunden "refreshen"?
    oder bin ich da auf dem falschen Weg?


    Das liegt nicht an dem Handler, sondern generall an deiner Architektur.


    Zum Server:
    Der Server ist (normalerweis) ein Programm das ohne Unterbrechnung läuft. Bei dir wird alle einmal im Konstruktor abgehandel und wieder beendet.
    Zu erst solltest du den Server ebenfalls in einem Thread lauf lassen, da ab Android 3.0(?) eine Exception geworfen wird. Das liegt daran das gewisse Methoden den aktuellen Thread, den Ui-Thread, blockieren und die somit die grafische Oberfläche "hängt".


    In der run-Methode erstellst du mittels einer while-Schleife und einer geeigneten Abrruchbedingung (Interrupt oder ähnliches) den eigentlichen Server-Code - das warten auf einen Client, Erstellung der Streams usw. (Im Konstruktor alles initialisieren und vorbereiten was du brauchst, damit der Server seine Arbeit verrichten kann. Darunter fällt auch dein Timer, der ja schon Teil des Servers sein sollte und nicht in der Main extra erstellt wird. Die Main sollte nur den Server starten.)
    Nicht vergessen, wenn der Server beendet werden soll, alles ordentlich zu schließen - Streams und den Socket.


    Wie vorher erwähnt gibt es Methoden die den Thread blockieren. In deinem Code wird nach dem sich ein Client verbunden hat auf eine Nachricht des Clients gewartet (die readline() blockiert bis die Nachricht gelesen wurde). Erst danach wird die aktuelle Zahl an den Client gesendet. Je nachdem was du vorhast, kann ja sein, dass das von dir so gewollt ist, empfiehlt es sich für den Empfang von Nachrichten des Clients ebenfalls ein extra Thread zu erstellen, sodass die Methoden sich nich gegenseitig blockieren. So wird auch unabhängig davon, ob der Client eine Nachricht senden will oder nicht, die aktuelle Zahl gesendet.


    Zum Client:
    So wie du den Client jetzt implementiert hast, wird vom Server auch nur was empfangen wenn auf den Senden-Button geklickt wurde. Es wird jedesmall eine neue Verbindung aufbauen. Besser wäre es nur einmal eine Verbindung aufzubauen und dann über die Verbindung Nachrichten senden und empfangen. Hier empfiehlt es sich das Empfangen in einen seperaten Thread auszulagern. Das Senden kann dabei im Ui-Thread bleiben da keine Methode diesen blockieren würde. Da der Server in einer (Endlos-)Schleife läuft wird nicht nur einmal die Zahl empfangen und auch nicht erst nachdem der Client eine Nachricht geschickt hat, sondern solange die Verbindung zum Server besteht.


    Noch ein paar Tipps:

    • Variablennamen werden am Anfang klein geschrieben
    • Keine neue Klassen innerhalb vom Code, das macht das Lesen nur schwieriger
    • Möglichst keine Warnungen ignorieren. Die Lint-Warnung besagt das es zu einem Leak führen kann, also den Handler static machen.


    Hoffe das ist halbwegs verständlich und hilft dir etwas. Was mir damals auch geholfen hat ist diese Seite hier: Client/Server-Anwendung.


    block_

  • Hallo,
    vielen Dank für die Antwort.
    Eigentlich ist der Clientcode unwichtig.
    Der Server soll nur wechselnde int Werte an den Client senden und der Client soll diese anzeigen.


    Der Client Code würde so aussehen.


    Der Servercode sieht jetzt so aus:



    Der Server verbindet sich mit dem Client sobald die Anwendung auf dem Client gestartet wird.
    Anschließend wird durch die Zeile

    Code
    System.out.println(x);

    in der Console der Wert 1,2,3,4,5,1,2,... usw ausgegeben.
    Frage:
    der Wert müsste eigentlich ja durch die Zeile darüber

    Code
    output.write(x);

    an den Client gesendet werden oder?
    Also müsste ich ja nur meinen Clientcode ändern oder?
    Gruß Brausebernd

  • Also der Server sieht schon so okay aus.


    Client:


    Jetzt kannst du eine Instanz von Verbindung erstellen und durch die Methode start() einfach starten lassen.

    Code
    Verbindung verbindung = new Verbindung();
    verbindung.start();


    Nun sollte immer die aktualisierte Zahl vom Server empfangen werden, solange der Thread läuft. Das Senden an den Server kannste normal um UI-Thread weitermachen, wie du es vorher hattest. Durch stop() sollte, die Verbindung dann geschlossen werden. Allerdings wird durch die Blockierung von der readline()-Methode das Schließen erst ausgeführt, nachdem eine weitere Nachricht empfangen wurde und somit die Schleife beendet werden konnte. Es gibt noch eine andere Methoden einen Thread zu beenden und zwar mit Interrupts, jedoch konnt ich das noch nicht testen, weil mein Eclipse streikt.


    Zu den Tipps nochmal:
    Die Namenskonventionen besagen, dass Variablennamen am Anfang klein geschrieben werden sollen. Zum Beispiel "NachrichtText" -> "nachrichtText".
    Für den Leak: static final Handler myHandler {...}
    Und zu der Klasse Verbindung: Verschiebe diese besser ans Ende der Datei, dadurch kann man den Code besser lesen, da die Klasse ansonsten logischen Gedanken unterbricht und man diese gegebenenfalls auch suchen muss (in deinem Fall nicht besonders schwer zu finden, aber wenn das Projekt größer werden könnte, oder mehrere Instanzen von Verbindung an unterschiedlichen Stellen benutzt werden).


    Falls weitere Probleme auftauchen, sag bescheid :)


    block_

  • Hallo,
    ich habe noch ein kleines Problem mit dem Code von block_.


    und zwar habe an dieser Stelle

    Code
    public Verbindung() 
    		{
    	
    				socket = new Socket("192.168.2.3", 4444);
    				input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    		
    		}


    die Meldung "Unhandle exception type IOExceptin"
    Dieses Problem sollte nicht mehr bestehen wenn ich mit Hilfe

    Code
    Verbindung verbindung = new Verbindung();
    verbindung.start();


    eine Instanz von Verbindung erstelle und diese starte.
    Meine Frage ist nun wo ich das in meinem Code einfügen muss.
    Danke
    Gruß
    Brausebernd

  • Da haben sich eine paar Fehler mit eingeschlichen, da ich das alles nur im Notepad geschrieben hab :P


    Den Konstruktor nochmal:


    Code
    public Verbindung() throws UnknownHostException, IOException {
    
    
    	socket = new Socket("192.168.2.3", 4444);
    	input = new BufferedReader(new InputStreamReader(
    			socket.getInputStream()));
    }


    und in deine onCreate schreibste folgendes:




    Hoffe das klappt jetzt so :)


    block_

  • Hallo,
    es funktioniert immer noch nicht.
    Er meckert rum das ich in der Main Netzwerk Aufgebaen durchführen will.
    Die LogCat sagt folgendes:


    08-29 07:43:57.790: D/AndroidRuntime(535): Shutting down VM
    08-29 07:43:57.790: W/dalvikvm(535): threadid=1: thread exiting with uncaught exception (group=0x40a3a1f8)
    08-29 07:43:57.800: E/AndroidRuntime(535): FATAL EXCEPTION: main
    08-29 07:43:57.800: E/AndroidRuntime(535): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.client/com.example.client.Client}: android.os.NetworkOnMainThreadException
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.app.ActivityThread.access$600(ActivityThread.java:123)
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.os.Handler.dispatchMessage(Handler.java:99)
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.os.Looper.loop(Looper.java:137)
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.app.ActivityThread.main(ActivityThread.java:4424)
    08-29 07:43:57.800: E/AndroidRuntime(535): at java.lang.reflect.Method.invokeNative(Native Method)
    08-29 07:43:57.800: E/AndroidRuntime(535): at java.lang.reflect.Method.invoke(Method.java:511)
    08-29 07:43:57.800: E/AndroidRuntime(535): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
    08-29 07:43:57.800: E/AndroidRuntime(535): at dalvik.system.NativeStart.main(Native Method)
    08-29 07:43:57.800: E/AndroidRuntime(535): Caused by: android.os.NetworkOnMainThreadException
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099)
    08-29 07:43:57.800: E/AndroidRuntime(535): at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:84)
    08-29 07:43:57.800: E/AndroidRuntime(535): at libcore.io.IoBridge.connectErrno(IoBridge.java:127)
    08-29 07:43:57.800: E/AndroidRuntime(535): at libcore.io.IoBridge.connect(IoBridge.java:112)
    08-29 07:43:57.800: E/AndroidRuntime(535): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
    08-29 07:43:57.800: E/AndroidRuntime(535): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
    08-29 07:43:57.800: E/AndroidRuntime(535): at java.net.Socket.startupSocket(Socket.java:566)
    08-29 07:43:57.800: E/AndroidRuntime(535): at java.net.Socket.tryAllAddresses(Socket.java:127)
    08-29 07:43:57.800: E/AndroidRuntime(535): at java.net.Socket.<init>(Socket.java:177)
    08-29 07:43:57.800: E/AndroidRuntime(535): at java.net.Socket.<init>(Socket.java:149)
    08-29 07:43:57.800: E/AndroidRuntime(535): at com.example.client.Client$Verbindung.<init>(Client.java:53)
    08-29 07:43:57.800: E/AndroidRuntime(535): at com.example.client.Client.onCreate(Client.java:35)
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.app.Activity.performCreate(Activity.java:4465)
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
    08-29 07:43:57.800: E/AndroidRuntime(535): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
    08-29 07:43:57.800: E/AndroidRuntime(535): ... 11 more


    kann man das alles nicht irgendwie total einfach lösen?
    ich will doch nur alle 2 Sekunden Daten vom Server empfangen. :(
    Gruß
    Brausebernd

  • Hi,


    Dinge wie Netzwerkabfragen darf man in Android nicht von dem Haupt Thread aus machen, das muss man in einen eigenen Thread auslagern. Würde sonst diverse Nebeneffekte haben, wie dass die Oberfläche einfriert usw. da deine Netzwerkabfrage andauernd 2 Sekunden schlafen will. Bau einfach eine eigene Java Klasse, die von Thread erbt und wirf das Teil in deiner Main dann an.


    Gruß,
    matze


    EDIT: ahja, wer lesen kann :D hättest du eh versucht. Vielleicht liegts an der inneren Klasse? mach da mal ne eigene bitte. Vielleicht auch mal die Kombination mit extends Thread anstatt implements Runnable, da kriegt man das ein oder andere geschenkt ....

  • Hallo,
    ich glaube eher das mein Servercode nicht ganz ok ist.
    Habe mich jetzt nochmal belesen und habe daraufhin folgenden Clientcode erstellt:


    rein vom logischen her, müsste der Client so funktionieren.
    Wenn ich nun aber eine Verbindung zum Server herstelle, kommt folgender Fehler


    java.net.SocketException: Software caused connection abort: socket write error
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(Unknown Source)
    at java.net.SocketOutputStream.write(Unknown Source)
    at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlush(Unknown Source)
    at sun.nio.cs.StreamEncoder.flush(Unknown Source)
    at java.io.OutputStreamWriter.flush(Unknown Source)
    at java.io.BufferedWriter.flush(Unknown Source)
    at server.Server$1.run(Server.java:45)
    at java.util.TimerThread.mainLoop(Unknown Source)
    at java.util.TimerThread.run(Unknown Source)


    Daraufhin habe ich den Servercode wie folgt angepasst:


    Jetzt wird alle 2 Sekunden ein neuer Wert n erzeugt.
    Wenn ich mich jetzt verbinde wird der aktuelle Wert zum Client gesendet und angezeigt.
    Das Problem liegt jetzt darin das ich die Ausgebe zum Client

    Code
    output.write(x);
    output.newLine();
    output.flush();


    irgendwie in die TimerTask implementieren müsste, kann mir da irgendeiner helfen?
    Gruß
    Brausebernd

  • Beim Testen von meinem Vorschlag hat alles soweit funktioniert und es wurde keine Exception geworfen. Habs jetzt mit dem Emulator nochmal getestet und den Fehler beseitig.



    Client:


    Verbindung:


    Server:


    block_

  • Der Code hat mir auch sehr geholfen, danke dafür an Alle die beteiligt waren.
    Ich habe bei meiner Anwendung festgestellt dass die Nachricht vom Server nicht sofort am Client angezeigt wird.


    Schickt der Server z.B. folgendes: test/r/n so wird erstmal nichts angezeigt, erst sobald ein weiteres Zeichen geschickt wird erscheint die Meldung am Client.
    Es muss jedoch kein zweites return nach dem Zeichen erfolgen, es reicht wie gesagt ein weiteres beliebiges Zeichen. Kann es sein dass der Bufferinhalt erst übergeben wird sobald er wieder mit neuen Daten befüllt wird?


    Danke


    Gruß snipor

  • Es ist natürlich \n \r :P Hab mich vertan ;)
    Als Client dient der Code hier aus Beitrag 13. Diesen hab ich einfach mal so übernommen.


    Als Server dient ein WIZFI 630 Modul, welches einfach die Daten von einer seriellen Schnittstelle auf einen TCP Port weitergibt.


    Danke


    snipor

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!