Socket Fehler

  • 18 Antworten
  • Letztes Antwortdatum
A

audacity363

Gast
Guten Tag

Ausgangssituation: Auf einem RaspberryPi läuft ein selbstgeschriebener EchoServer an den ich die Zahlen 1-17 schicken kann und dementsprechend werden die GPIO Ports aktiviert. Da ich noch ein Neuling im Android Coding bin habe ich mal ein wenig Gegoogelt und mehrere Möglichkeiten gefunden wie das realisiert werden könnte:

Code:
public void Client()
	{
		try 
		{
			so = new Socket("raspberrypi", 7);
		} 
		catch (Exception e) 
		{
			Log.d("TCP", "UnknownHostException");
		} 
		
		
		if(so == null)
		{
			Log.d("TCP", "keine Verbindung");
		}
		else
		{
			Log.d("TCP", "Verbindung erfolgreich");
		}
		

		try 
		{
			pw = new PrintWriter(so.getOutputStream(),true);
			pw.write("1");
			pw.close();
		}
		
		catch (IOException e) 
		{
			Log.d("Fehler", "PrintWriter IOException");
		}	

		Log.d("Thread", "ENDE");
	}

Code:
 public void Client(String Nummer, String Server) 
    {

     try 
     {

             InetAddress serverAddr = InetAddress.getByName(Server);

             Log.d("TCP", "C: Connecting...");

             Socket socket = new Socket(serverAddr, 7);

             String message = "Hello from Client android emulator";



                 try 
                 {

                     Log.d("TCP", "C: Sending: '" + message + "'");

                     PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);

                     out.println(Nummer);

                     Log.d("TCP", "C: Sent.");

                 Log.d("TCP", "C: Done.");

                     

         } 
                 catch(Exception e) 
                 {

             Log.e("TCP", e.toString());



                 } 
                 finally 
                 {

                    socket.close();

                  }



     } 
     catch (Exception e) 
     {

          Log.e("TCP", e.toString());

     }

}


Nur beide Versionen funktionieren nicht. Bei der ersten stürtzt die App ab sobald ich es ausführe. Bei der zweiten Version passiert gar nichts. Nichtmal die Logs werden ausgegeben.
 
Hey ho,

1) Netzwerk Kommunikation in eigenen Thread ausgelagert?
2) Permissions gesetzte?

lg. Dagobert
 
1.) Nein da das ganze jeweils in einer eigenen Klasse liegt und wenn ein Button gedrückt wird, wird diese Klasse mit den richtigen Parametern aufgerufen.

2.) Was meinst du mit Permissions? Auf dem Handy oder aufm Server?
 
Ich schlage dir vor ;) Beschäftige dich ein paar Stunden mit Android und Doku..

und dann stelle nochmal deine Fragen...

Android Netzwerk Tutorial

lg. Dagobert
 
Hab mich schoon mit Android beschäftigt zumindest die Grundlagen. :)) Dn rest hab ich mir zusammengegoogelt. Werd mir deine Sachen nachher nochmal ansehen(Hoffe mal das ich dran kommme weil ich unterwegs bin).
Melde mich dann. Schonmal vielen Dank.
 
Ok da bin ich wieder. Also: Ich hab jetzt die Permission "android.permission.INTERNET" hinzugefügt. Jetzt hab ich das Problem, dass der Emulator keine Netzwerkverbindung hat und deswegen sagt: android.os.NetworkOnMainThreadException. Wenn ich das ganze jetzt Exportiere um es auf dem Handy zu starten löscht er die Rechte Verteilung wieder und die App stürzt wieder ab. Wahrscheinlich weil die Rechte nicht gegeben sind.
 
Natürlich funktionieren die Berechtigungen (und mit hoher Wahrscheinlichkeit das Netzwerk). Vielleicht solltest Du mal Deinen Stacktrace lesen. Stichwort: NetworkOnMainThreadException.
 
Und da kommen wir wieder zu:

DagobertDokate schrieb:
Hey ho,

1) Netzwerk Kommunikation in eigenen Thread ausgelagert?
2) Permissions gesetzte?

lg. Dagobert
 
Also das ganze funktioniert jetzt einmalig. Wenn ein Button gedrückt wird startet er den Thread und setzt den Text auf ON bzw. OFF. Das ganze wird auch ordentlich beendet aber sobald das ganze aber noch einmal aufgerufen wird, stürtzt die App ab mit folgender Fehlermeldung: Thread already started.
Der Thread muss aber immer wieder gestartet werden da ich ja immer verschiedene Nummern rüber schicke.
 
Dann beendet sich dein Thread nicht.
Warum auch immer.. oder du versuchts zu schnell einen neuen Thread aufzumachen wenn der Alte noch nicht beendet ist.

Wie sieht denn der Code zu deinem Thread aus?
nutzt du AsyncTaks? oder hast du dir was eigenes gebaut?
 
Also ich benutz die ganze normalen Java Befehle für das ganze:

Thread:
Code:
@Override	
        public void run() 
        {
			Log.e("TCP", "Run Thread");
         try {
 
                 InetAddress serverAddr = InetAddress.getByName("raspberrypi");
 
                 Log.d("TCP", "C: Connecting...");
 
                 Socket socket = new Socket(serverAddr, 7);
 
                 String message = "1";
 
 
 
                 try 
                 {
 
                	 Log.d("TCP", "C: Sending: '" + message + "'");
 
                     PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
                     out.println(message);
 
                     Log.d("TCP", "C: Sent.");
 
                     Log.d("TCP", "C: Done.");
 
                         
 
             } 
 
             catch(Exception e) 
             {
 
                 Log.e("TCP", "S: Error", e);
                 
             } 
             finally 
             {
            	
 
            	 socket.close();
            	 Log.e("TCP", "Close");
             }
 
 
 
         } 
         catch (Exception e) 
         {
 
              Log.e("TCP", "C: Error", e);
 
         }
 
    }

so wird das ganze aufgerufen:

Code:
public void onClick(View e) 
	{
		if(e.getId() == b1.getId())
		{
			if(status[0] == 0)
			{
				Log.e("TCP", "if");
				Box1.setText("ON");
				status[0] = 1;
				
				t1.start();
				
				
				
				
			}
			else
			{
				Log.e("TCP", "else");
				Box1.setText("OFF");
				status[0] = 0;
				
			}
 
Ein Thread kann nur einmal gestartet werden. Dann terminiert er irgendwann. Ob das sofort (wie bei Dir), auf Anfrage oder auf Zwang passiert ist dem Nutzer oder den Umständen überlassen. Eine Wiederverwendung ist nicht vorgesehen und daher verboten. Lies einfach mal die Exceptions …

Dokumentation zu Thread:It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.

Threading ist alles andere als eine einfache Sache. Es wird noch komplizierter, da Du Inkonsistenzen und Deadlocks vermeiden möchtest und bestimmt mit dem UI-Thread kommunizieren möchtest.
 
Zuletzt bearbeitet:
Also kurz gesagt: Die Sachen in der Android Umgebung verhalten sich ganz anderes als in Java. Also ich habe jetzt noch folgendes Versucht:
Der Client läuft von Anfang an in einer Endlosschleife und wartet auf eine Eingabe:

Code:
while(nummer == 0)
				{
					Log.e("nummer", "while");
					try 
					{
						Thread.sleep(1000);
					} 
					catch (InterruptedException e) 
					{
						
					}
					
					if (nummer != 0)
					{
						Log.e("nummer", "if");
						break;
					}
				}

Nur bleibt er da im while hängen sehr wahrscheinlich weil sich da das Android Java wieder anderes verhält. Die Variable "nummer" wird dann verändert wenn ein Button gedrückt wird.
 
Nein die Doku ist aus dem "normalen" Java.
Du darfst halt nicht t1.start() mehrfach aufrufen.

Sondern musst beispielsweise mit t1 = new Thread(); einen neuen erstellen. (mit deiner passenden Thread Klasse natürlich).

Und was dein while angeht.
Das kann auch nicht funktionieren, Wann soll denn nummer gesetzt werden?
Du gehst in die Schleife rein machst sleep für 1 Sekunde und in dieser Zeit friert deine Anwendung quasi ein, sprich egal wo du hindrückst, keiner dieser TouchEvents wird verarbeitet weil dein Thread schläft.
Selbst ohne sleep würde niemals eines dieser events verarbeitet werden, wenn du im gleichen Thread bist.

Ich sehe hier überhaupt kein Unterschied zum "normalen" Java, da funktioniert das auch nicht was du vorhast.

Das etwas besondere an Android ist, dass man gezwungen wird z.B. Netzwerkaktivitäten in einem eigenen Thread laufen zu lassen. Aus gutem Grund.
in einer normalen Java Anwendung könntest du den Netzwerkkram einfach reinschreiben, nur friert die Anwendung bis die Netzwerkanfrage beendet ist auch ein.
 
  • Danke
Reaktionen: audacity363
Java unter Android verhält sich nicht anders, ausser das es zum Teil vielleicht etwas strikter ist (Wie beim Beispiel mit der Netzwerk-Kommunikation im Main-Thread). Das ganze ist aber aus gutem Grund so. Darauf gehe ich jetzt mal nicht weiter ein, aber falls es dich genauer interessiert: Keeping Your App Responsive

Dein letzter Versuch kann so nicht funktionieren. Wenn du im GUI-Thread ein sleep hast, dann reagiert das GUI natürlich in dieser Zeit nicht, deshalb kannst du auch keine Buttons drücken. Ist aber auf dem PC genauso
 
Also ich hab das ganze schon aufm Rechner mit Java Realisiert und möchte es jetzt halt mobil machen.
Um es vll. ein wenig genauer zu beschreiben: Der Client liegt in einer eigenen Datei damit da kein Durcheinander entsteht.
Der sleep Befehl liegt ja im Netzwerk Thread und friert ja nur diesen damit ein um immer ein wenig Zeit zu haben um auf die Variable nummer zu warten, auf die in der MainActivity zugegriffen wird. Je nach Button wird dort eine Zahl von 1 -17 reingeschreiben um dem Server diese zu schicken. Da aber nicht zwei Threads auf die gleiche Variable zugreifen können friere ich den Netzwerk Thread ein um von außen drauf-zugreifen zu können.

Der ursprüngliche Beitrag von 15:17 Uhr wurde um 15:36 Uhr ergänzt:

OK hab es jetzt so gelöst wie du es vorgeschlagen hast:

Vor jedem Thread start deklariere ich den Thread nochmal neu und übergebe mit Hilfe des Konstruktor die Variablen die ich brauch.

Code:
public class Client implements Runnable
{    	      
	String nummer = "";
	String Server = "";
	
	public Client(String nummer1, String Server1)
	{
		nummer = nummer1;
		Server = Server1;		
	}
	
		public void run() 
        {
			...
        }
}

Aufgerufen wird das ganze dann mit:
Code:
  public void onClick(View e) 
	{
		if(e.getId() == b1.getId())
		{
			if(status[0] == 0)
			{
				Log.e("TCP", "if");
				Box1.setText("ON");
				status[0] = 1;				
				Thread t1 = new Thread(new Client("", ""));
				t1.start();
	
			}
			else
			{
				Log.e("TCP", "else");
				Box1.setText("OFF");
				status[0] = 0;
				
			}
			
		}
}

ABER jetzt habe ich immer noch das Problem mit dem Exportieren zur APK. Sobald ich die APK erstellen lasse werden alle Permissions gelöscht und die App läuft nicht auf dem Handy.
 
Das mit den Permissions kann ich dir jetzt auch nicht sagen.. was heißt denn die werden gelöscht?
Wenn du die App installierst sollte er dir doch anzeige welche Permission die App braucht und die Liste ist leer?

Du hattest halt geschrieben der Client läuft die ganze zeit in einer endlos schleife, aber der client soll doch auch die daten von dem server holen.
Ich versteh halt nicht so ganz genau was du überhaupt vorhast.

Aber ich würde mir an deiner Stelle mal AsyncTask angucken.
Das ist eine Hilfsklasse für operationen die in einem anderen Thread laufen sollen.
Da hast du dann auch beispielsweise eine onPostExecute Methode die (im UI Thread) aufgerufen wird um nachdem du die Daten geladen hast damit weiter zu arbeiten.
 
zu 1.): In Eclipse kann man diese ja auf einer GUI in das Manifest eintragen. Sobalt ich die APK erstelle wird dieser Eintrag gelöscht habe dir dazu mal schnell ein Video hochgeladen(rechte - YouTube).

Also zur Funktion:
Jeder Button stellt ein Pin des RaspberryPi da. Auf dem RaspberryPi läuft ein Server auf Port 7 der diese dementsprechend aktivieren kann. Der Client schickt eine Zahl von 1-17. Wenn er zwar was bekommen hat dies aber nicht verarbeiten kann weil irgendwas verloren gegangen ist schickt er das zurück und der Client schickt die Zahl nochmal neu. Wenn alles gut gelaufen ist schickt er dies zurück und der Client wird beendet.
 
Okey ich bin ein Idiot :D Habe die falsche Manifest Datei genommen... Jetzt funktioniert auch alles.
 
Zuletzt bearbeitet:

Ähnliche Themen

tarek857
Antworten
4
Aufrufe
423
tarek857
tarek857
Zurück
Oben Unten