Objekt serialisieren

PC-Beim Drücken eines Buttons wird die Methode broadcastSignal(String signal) aufgerufen, die
eine Nachricht an alle Smartphones schickt die mit dem Server verbunden sind. (Funktioniert)

public synchronized void broadcastSignal(String signal)
	{
		Socket signalSocket;
		PrintWriter printWriter;
		ListIterator<Socket> listIterator = signalSocketList.listIterator(); //Sockets zu den Smartphones
	
		while(listIterator.hasNext())
		{
			signalSocket = listIterator.next();
			try 
			{
				printWriter = new PrintWriter(signalSocket.getOutputStream(), true);
				printWriter.println(signal);
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
       }

Smartphone - Sobald der Server eine Nachricht verschickt hat über die Methode broadcastSignal(String signal)
kommt sie an jedem Smartphone an. (Funktioniert)

public class SignalClientThread extends Thread
{
	private String ip;
	private int port;
	private String signal;
	private BufferedReader in;
	private PrintWriter out;
	private Socket clientSocket;
	
	public SignalClientThread(String ip, int port)
	{
		this.ip = ip;
		this.port = port;
	}
	
	
	public void run()
	{		
		try 
		{
			this.clientSocket = new Socket(ip, port);	
			this.clientSocket.setKeepAlive(true);
			this.clientSocket.setSoTimeout(0);
			this.in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
			this.out = new PrintWriter(this.clientSocket.getOutputStream(), true);
			boolean run = true;
			
			SingletonSocketHandler.getInstance().createChatClientThread(ip, port);
			
			while(run)
			{
				this.signal = this.in.readLine();
					 
					 StatusInfo.currentActivity.runOnUiThread(new Runnable() {

	                        @Override
	                        public void run() 
	                        {
	                        	Toast.makeText(StatusInfo.currentActivity, signal, Toast.LENGTH_SHORT).show();
	                        }
	                    });
			}
            }
       }
}

PC-Über einen Button wird die Methode broadcastDataInfoNetwortTopology() aufgerufen,
welche über oubjectOutputStream.writeObject(dataInfoNetworktTopology) ein Objekt an
alle am Server verbunden Smartphones schicken soll.
Dies Funktioniert allerdings höchstes beim ersten Aufruf der Methode broadcastDataInfoNetworkTopology().
Bei einem erneuten Aufruf der Methode broadcastDataInfoNetworkTopology() kommt an den Smartphones nichts mehr an. Die readObject
Methode bei den Smartphones wartet und wartet und nix kommt mehr ab dem zweiten Aufruf.
Wenn ich zur Kommunikation mit jedem Smarpthone jedes ObjectOutputStream = new ObjectOutputStream(dataSocket.getOutputStream), außerhalb
der Methode broacastDataInfoNetworkTopology() speicher funktioniert alles und die Objekte kommen auch bei den Smartphones an.
Wenn ich den Code aber so lasse wie unten gezeigt, also wenn ich bei jedem Aufruf der Methode broadcastDataInfoNetworkTopology()
das ObjectOutputStream Object für jedes Smartphone neu erstelle scheitert es, obwohl ich darin die bereits erstellten Sockets (dataSocket.getOutputStream()) wiederverwende. Ich erstelle also nur die ObjectOutputStreams neu nicht aber die eigentlichen Sockets, die alten Sockets werden wiederverwendet.
Bei der obigen Methode broadcastSignal(String signal) erstelle ich doch auch immer wieder einen neuen PrintWriter und überge die bereits
erstellten Sockets und es funktioniert.
Warum funktioniert das also nicht auch bei broadcastDataInfoNetworkTopology(), das ist doch im Prinzip analog?

	public synchronized void broadcastDataInfoNetworkTopology()
	{
		Socket dataSocket;
		ObjectOutputStream objectOutputStream; 
		ListIterator<Socket> listIterator = dataSocketList.listIterator(); //Sockets zu den Smartphones
		
		while(listIterator.hasNext())
		{
			dataSocket = listIterator.next();
			try 
			{
                                //funktioniert nur beim ersten Aufruf der Methode broadcastDataInfoNetworkTopology(),
                                // bei einem weiteren Aufruf der Methode broadcastDataInfoNetworkTopology() kommt am Smarpthone nichts an
                                //Damit bei einem weiteren Aufruf beim Smarphone ein Objekt ankommt, muss ich ein Attribut 
                                //von ObjectOutputStream außerhalb der Methode definieren und ihm new ObjectOutputStream(...) zuweisen.
                                //Warum funktioniert das so nicht? Das ist doch Analog zu broadcastSignal(String signal), s.o. 
				objectOutputStream = new ObjectOutputStream(dataSocket.getOutputStream()); 
          
				DataInfoNetworkTopology dataInfoNetworkTopology = new DataInfoNetworkTopology(this.facadeModel.getModelNetworkTopology().getHmNetworkTopology(), "test");

				objectOutputStream.writeObject(dataInfoNetworkTopology);
				objectOutputStream.reset();				
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}

Smartphone-erhält das vom Sender verschickte Objekt.

public class DataClientThreadReceive extends Thread
{
	private InputStream in;
	private HashMap <String, HashMap<String, Boolean>> hmNetworkTopology; 
	
	public DataClientThreadReceive(InputStream in)
	{
		this.in = in;
	}
	
	
	public void run()
	{
		try
		{
			ObjectInputStream objectInputStream = new ObjectInputStream(this.in);
			boolean run = true;//richtig positionieren
			
			while(run)
			{	
				Object dataInfoObject = objectInputStream.readObject();
				
				StatusInfo.currentActivity.runOnUiThread(new Runnable() {

                    @Override
                    public void run() 
                    {
                    	Toast.makeText(StatusInfo.currentActivity, "DataInfoNetworkTopology: nach readObject", Toast.LENGTH_LONG).show();
                    }
				});
                   }
              }
        }
}

Ein Stream-Write, bei dem auf der anderen Seite scheinbar nichts ankommt, kann an einem Puffer liegen, der noch nicht vollständig gefüllt ist, um die Schreiboperation tatsächlich auszuführen. ein Stream.flush() veranlasst das vorzeiteige Schreiben in diesen Fällen. Versuche das mal.

Ganz analog zur broadcast-String-Methode ist das broadCast-Object nicht, da Du hier einen PrintWriter verwendest, der sehr ganz anders funktioniert als ein ObjectOutputStream.

In beiden Fällen unschön, unüblich und überflüssig ist, dass Du in den broadcast Methoden jedesmal einen neuen Writer bzw. OutputStream erzeugst. Erzeuge diese einmalig z.B. unmittelbar nach Aufbau der Socketverbindung.
Falls beide broadCast Methoden über das selbe Socket kommunizieren, dann verwende in diesem Fall am ausschließlich einen gemeinsamen ObjectOutputStream zum Broadcast von Signal und DataInfoNetworkTopology.

Das besondere an ObjectOutputStreams ist, dass diese zusätzlich zum eigentlichen Inhalt beim Verbindungsaufbau einen Header übertragen, der beim erzeugen eines ObjectInputStreams zunächst einmal verifiziert wird. Das könnte in Deinem Fall die Probleme verursachen.

Das ist nur ein „Teil“ der Besonderheit. Das wirklich besondere ist, dass der ObjectOutputStream (OOS) einmal gesendete Objekte cached. D.h. wenn du ein Objekt erneut überträgst, aber seit dem letzten Senden eine Variable im Objekt geändert hast, so wird diese Änderung nicht mitgeschickt. Der OOS erkennt: Ah, das Objekt hab ich schon mal gesendet, und damals hab ich es mit ID ‚xyz‘ referenziert. Also sende ich nur nochmal die ID ‚xyz‘ und der Empfänger weiß dann, dass es das gleiche Objekt von „vorhin“ ist.

Um das zu „umgehen“ muss man den OOS zurücksetzen. Schau dazu am besten mal die reset() des OOS Methode im JavaDoc an.

Das stimmt. Das Cachen bzw. die reset() Methode scheint laut gepostem Code bereits bekannt zu sein, daher hatte ich das explizit nicht erwähnt.

Oh, hätte den Code doch etwas ausführlicher lesen sollen… :o

Ich war ja auch schon am Überlegen, ob der Methodenaufruf da evtl. zufällig reingerutscht ist und im Failure Fall vielleicht nicht genutzt wurde. Aber im konkreten Code hat die Methode ja keinen Effekt. Daher habe ich mal angenommen, dass die Methode in allen Fällen genutzt wurde.

Okay danke für die Hinweise